diff --git a/CXM_message_constants.anubis b/CXM_message_constants.anubis index ce354b2..4e95a21 100644 --- a/CXM_message_constants.anubis +++ b/CXM_message_constants.anubis @@ -1,152 +1,158 @@ -/* - * - * User: David RENE - * Date: 07/04/2007 - * Time: 16:06 - * (c) Calexium - * - */ - -public define Word32 _NO_NAME_MSG = 0x00000000. - -// **************** MAILBOX PROTOCOL *************** - -public define Word32 _C_SCAN_FOR_BOXES = 0x33770001. // Ask Boxes to publish their informations -public define Word32 _C_PUBLISH_BOX_STATUS = 0x33770002. // Used by Boxes to publish their informations -public define Word32 _C_SHUTDOWN_BOX = 0x33770003. // Used to ask a box to shutdown -public define Word32 _CXM_SET_BOX_NETWORK_PARAMS = 0x33770004. // Define network configuration of boxes -public define Word32 _CXM_RESET_ADMIN_PWD = 0x33770005. // Ask the MailFountain to reset the admin pwd. -public define Word32 _CXM_FULL_RESET = 0x33770006. // Ask the MailFountain to proceed to a full reset of its data. After that, the MailFountain is totally empty (mail, config, domain, logs, etc...) -public define Word32 _CXM_FORCE_PUBLISH_MF_CONFIG = 0x33770007. // Ask the MailFountain to proceed a Config publishing to DomainManager - - // **************** PACKAGE BUILDER *************** - -public define Word32 _CXM_PKG_MSG_BASIS = 0x33770400. // -public define Word32 _CXM_PKG_CONTAINER = 0x33770401. -public define Word32 _CXM_PKG_HEADER_PART = 0x33770402. // Header Message for Script -public define Word32 _CXM_PKG_SCRIPT_PART = 0x33770403. // Main Message for Script -public define Word32 _CXM_PKG_S_ADD_FILE = 0x33770404. // script action to add file in the destination -public define Word32 _CXM_PKG_S_RUN = 0x33770405. // script action to run a command -public define Word32 _CXM_PKG_INDEX_PART = 0x33770440. // ID of package Index part -public define Word32 _CXM_PKG_IDX_ENTRY = 0x33770441. // Index entry information - - // **************** UPDATE SERVICE *************** - -public define Word32 _CXM_UPDATE_SERVICE_MSG_BASIS = 0x33770800. // -public define Word32 _CXM_UPD_SERVICE_ID = 0x33770801. -public define Word32 _CXM_UPD_HAS_UPDATE = 0x33770802. // -public define Word32 _CXM_UPD_LIST_CLASS_FILES = 0x33770803. // List the files contained in the class path - - // **************** SERVICE NEGOCIATION *************** - -public define Word32 _CXM_SERVICE_NEGOCIATION_BASIS = 0x33770C00. // -public define Word32 _CXM_REQUEST_FOR_SERVICE = 0x33770C01. // -public define Word32 _CXM_LOGIN = 0x33770C02. // - - // **************** GENERIC PROTOCOL *************** - -public define Word32 _CXM_GENERIC_PROTOCOL_BASIS = 0x33771000. // -public define Word32 _CXM_ACK = 0x33771001. // -public define Word32 _CXM_ACK_RESULT_MSG = 0x33771002. // - - // **************** FTP SERVICE *************** - -public define Word32 _CXM_FTP_SERVICE_MSG_BASIS = 0x33771400. // -public define Word32 _CXM_FTP_SERVICE_ID = 0x33771401. -public define Word32 _CXM_FTP_GET_FILE = 0x33771402. -public define Word32 _CXM_FTP_START_TRANSFERT = 0x33771403. -public define Word32 _CXM_FTP_DATA = 0x33771404. - - // ************** LOGGER SERVICE ************** - -public define Word32 _CXM_LOGGER_SERVICE_MSG_BASIS = 0x33771800. // -public define Word32 _CXM_LOGGER_SERVICE_ID = 0x33771801. -public define Word32 _CXM_LOGGER_LOG = 0x33771802. - - // ************** DOMAIN SERVICE ************** - -// MF <-> DomainManager -public define Word32 _CXM_DOMAIN_SERVICE_MSG_BASIS = 0x33771C00. // -public define Word32 _CXM_DOMAIN_SERVICE_ID = 0x33771C01. -public define Word32 _CXM_DOMAIN_PUBLISH_MF_CONFIG = 0x33771C02. -public define Word32 _CXM_DOMAIN_GET_NAME = 0x33771C03. -public define Word32 _CXM_DOMAIN_GET_MY_IP = 0x33771C04. -public define Word32 _CXM_DOMAIN_PUBLISH_MY_IP = 0x33771C05. -public define Word32 _CXM_DOMAIN_PUBLISH_DYN_TEST = 0x33771C06. -public define Word32 _CXM_DOMAIN_GET_STATUS = 0x33771C07. -public define Word32 _CXM_DOMAIN_GET_DOMAIN_INFO = 0x33771C08. -public define Word32 _CXM_DOMAIN_CRITICAL_ALERT = 0x33771C09. -public define Word32 _CXM_DOMAIN_COMMAND_RESULT = 0x33771C0A. - - -// DomainManager <-> Gandi -public define Word32 _CXM_GANDI_SERVICE_ID = 0x33771D00. -public define Word32 _CXM_GANDI_CHECK_AVAILABILITY = 0x33771D01. // 'NAME' (String): Base names (without extension) of the wanted domains - // --> CXM_ACK with 'DOMAINS' (String): Array of avaiblable domains -public define Word32 _CXM_GANDI_CREATE_CONTACT = 0x33771D02. // 'CLASS' (String): - // 'FIRSTNAME', 'LASTNAME', 'ADDRESS', 'ZIPCODE', 'CITY', 'COUNTRY', 'PHONE', 'EMAIL' (String) - // --> CXM_ACK with 'CONTACT_HANDLE' (String): Created handle for this contact -public define Word32 _CXM_GANDI_CREATE_DOMAIN = 0x33771D03. // 'DOMAIN' (String): Domain full name - // 'OWNER' (String): Owner handle - // --> CXM_ACK with 'DOMAIN_HANDLE' (String): Created handle for this domain - // ************** MF INSTALLER SERVICE ************** - -public define Word32 _CXM_INSTALLER_SERVICE_MSG_BASIS= 0x33772000. -public define Word32 _CXM_INSTALLER_SERVICE_ID = 0x33772001. -public define Word32 _CXM_INSTALLER_REGISTER_APP_ID = 0x33772002. -public define Word32 _CXM_INSTALLER_GET_NEW_SERIALS = 0x33772003. -public define Word32 _CXM_INSTALLER_CONFIRM_SERIALS_PUBLICATION = 0x33772004. -public define Word32 _CXM_INSTALLER_GET_MODELS = 0x33772005. // returns the MF models list - -// ************************************************* -// ************* MF API ************* - -// ************* ACCOUNTS SERVICE ************* - -public define Word32 _CXM_ACCOUNT_SERVICE_MSG_BASIS = 0x33772100. - -// ************* MAILINGS SERVICE ************* - -public define Word32 _CXM_MAILING_SERVICE_MSG_BASIS = 0x33772200. -public define Word32 _CXM_MAILING_SERVICE_ID = 0x33772200. // same as MSG_BASIS - -public define Word32 _CXM_MAILING_CREATE_CONTACT = 0x33772201. -public define Word32 _CXM_MAILING_UPDATE_CONTACT = 0x33772202. -public define Word32 _CXM_MAILING_DELETE_CONTACT = 0x33772203. - -public define Word32 _CXM_MAILING_CREATE_MAILING = 0x33772211. -public define Word32 _CXM_MAILING_UPDATE_MAILING = 0x33772212. -public define Word32 _CXM_MAILING_DELETE_MAILING = 0x33772213. - -public define Word32 _CXM_MAILING_ADD_CONTACT_TO_MAILING = 0x33772221. -public define Word32 _CXM_MAILING_REMOVE_CONTACT_FROM_MAILING = 0x33772222. - - -// ************* DIRECTORY SERVICE ************* - -public define Word32 _CXM_DIRECTORY_SERVICE_MSG_BASIS = 0x33772300. - -// ************* BACKUP SERVICE ************* - -public define Word32 _CXM_BACKUP_SERVICE_MSG_BASIS = 0x33772400. -public define Word32 _CXM_BACKUP_SERVICE_ID = 0x33772401. -public define Word32 _CXM_BACKUP_GET_STATUS = 0x33772402. /// Get backup status for a given MF (can subscribe, subscribed, subscription end date...) -public define Word32 _CXM_BACKUP_STARTING_BACKUP = 0x33772403. /// Notify BackupService that backup process is starting -public define Word32 _CXM_BACKUP_FINISHING_BACKUP = 0x33772404. /// Notify BackupService that backup process is finishing -public define Word32 _CXM_BACKUP_STARTING_RESTORE = 0x33772405. /// Notify BackupService that restore process is starting -public define Word32 _CXM_BACKUP_FINISHING_RESTORE = 0x33772406. /// Notify BackupService that restore process is finishing - -// ************* STATISTICS SERVICE ************* - -public define Word32 _CXM_STATS_SERVICE_MSG_BASIS = 0x33772500. - -// ************* SUPERVISER SERVICE ************* - -public define Word32 _CXM_SUPERVISER_SERVICE_MSG_BASIS = 0x33772600. -public define Word32 _CXM_SUPERVISER_SERVICE_ID = 0x33772600. -public define Word32 _CXM_SUPERVISER_GET_STATUS = 0x33772601. - -// ************************************************* -// ************* KERO_PBX API ************* - -public define Word32 _CXM_KERO_PBX_MSG_BASIS = 0x33780000. // Ask Boxes to publish their informations +/* + * + * User: David RENE + * Date: 07/04/2007 + * Time: 16:06 + * (c) Calexium + * + */ + +public define Word32 _NO_NAME_MSG = 0x00000000. + +// **************** MAILBOX PROTOCOL *************** + +public define Word32 _C_SCAN_FOR_BOXES = 0x33770001. // Ask Boxes to publish their informations +public define Word32 _C_PUBLISH_BOX_STATUS = 0x33770002. // Used by Boxes to publish their informations +public define Word32 _C_SHUTDOWN_BOX = 0x33770003. // Used to ask a box to shutdown +public define Word32 _CXM_SET_BOX_NETWORK_PARAMS = 0x33770004. // Define network configuration of boxes +public define Word32 _CXM_RESET_ADMIN_PWD = 0x33770005. // Ask the MailFountain to reset the admin pwd. +public define Word32 _CXM_FULL_RESET = 0x33770006. // Ask the MailFountain to proceed to a full reset of its data. After that, the MailFountain is totally empty (mail, config, domain, logs, etc...) +public define Word32 _CXM_FORCE_PUBLISH_MF_CONFIG = 0x33770007. // Ask the MailFountain to proceed a Config publishing to DomainManager + + // **************** PACKAGE BUILDER *************** + +public define Word32 _CXM_PKG_MSG_BASIS = 0x33770400. // +public define Word32 _CXM_PKG_CONTAINER = 0x33770401. +public define Word32 _CXM_PKG_HEADER_PART = 0x33770402. // Header Message for Script +public define Word32 _CXM_PKG_SCRIPT_PART = 0x33770403. // Main Message for Script +public define Word32 _CXM_PKG_S_ADD_FILE = 0x33770404. // script action to add file in the destination +public define Word32 _CXM_PKG_S_RUN = 0x33770405. // script action to run a command +public define Word32 _CXM_PKG_INDEX_PART = 0x33770440. // ID of package Index part +public define Word32 _CXM_PKG_IDX_ENTRY = 0x33770441. // Index entry information + + // **************** UPDATE SERVICE *************** + +public define Word32 _CXM_UPDATE_SERVICE_MSG_BASIS = 0x33770800. // +public define Word32 _CXM_UPD_SERVICE_ID = 0x33770801. +public define Word32 _CXM_UPD_HAS_UPDATE = 0x33770802. // +public define Word32 _CXM_UPD_LIST_CLASS_FILES = 0x33770803. // List the files contained in the class path + + // **************** SERVICE NEGOCIATION *************** + +public define Word32 _CXM_SERVICE_NEGOCIATION_BASIS = 0x33770C00. // +public define Word32 _CXM_REQUEST_FOR_SERVICE = 0x33770C01. // +public define Word32 _CXM_LOGIN = 0x33770C02. // + + // **************** GENERIC PROTOCOL *************** + +public define Word32 _CXM_GENERIC_PROTOCOL_BASIS = 0x33771000. // +public define Word32 _CXM_ACK = 0x33771001. // +public define Word32 _CXM_ACK_RESULT_MSG = 0x33771002. // + + // **************** FTP SERVICE *************** + +public define Word32 _CXM_FTP_SERVICE_MSG_BASIS = 0x33771400. // +public define Word32 _CXM_FTP_SERVICE_ID = 0x33771401. +public define Word32 _CXM_FTP_GET_FILE = 0x33771402. +public define Word32 _CXM_FTP_START_TRANSFERT = 0x33771403. +public define Word32 _CXM_FTP_DATA = 0x33771404. + + // ************** LOGGER SERVICE ************** + +public define Word32 _CXM_LOGGER_SERVICE_MSG_BASIS = 0x33771800. // +public define Word32 _CXM_LOGGER_SERVICE_ID = 0x33771801. +public define Word32 _CXM_LOGGER_LOG = 0x33771802. + + // ************** DOMAIN SERVICE ************** + +// MF <-> DomainManager +public define Word32 _CXM_DOMAIN_SERVICE_MSG_BASIS = 0x33771C00. // +public define Word32 _CXM_DOMAIN_SERVICE_ID = 0x33771C01. +public define Word32 _CXM_DOMAIN_PUBLISH_MF_CONFIG = 0x33771C02. +public define Word32 _CXM_DOMAIN_GET_NAME = 0x33771C03. +public define Word32 _CXM_DOMAIN_GET_MY_IP = 0x33771C04. +public define Word32 _CXM_DOMAIN_PUBLISH_MY_IP = 0x33771C05. +public define Word32 _CXM_DOMAIN_PUBLISH_DYN_TEST = 0x33771C06. +public define Word32 _CXM_DOMAIN_GET_STATUS = 0x33771C07. +public define Word32 _CXM_DOMAIN_GET_DOMAIN_INFO = 0x33771C08. +public define Word32 _CXM_DOMAIN_CRITICAL_ALERT = 0x33771C09. +public define Word32 _CXM_DOMAIN_COMMAND_RESULT = 0x33771C0A. + + +// DomainManager <-> Gandi +public define Word32 _CXM_GANDI_SERVICE_ID = 0x33771D00. +public define Word32 _CXM_GANDI_CHECK_AVAILABILITY = 0x33771D01. // 'NAME' (String): Base names (without extension) of the wanted domains + // --> CXM_ACK with 'DOMAINS' (String): Array of avaiblable domains +public define Word32 _CXM_GANDI_CREATE_CONTACT = 0x33771D02. // 'CLASS' (String): + // 'FIRSTNAME', 'LASTNAME', 'ADDRESS', 'ZIPCODE', 'CITY', 'COUNTRY', 'PHONE', 'EMAIL' (String) + // --> CXM_ACK with 'CONTACT_HANDLE' (String): Created handle for this contact +public define Word32 _CXM_GANDI_CREATE_DOMAIN = 0x33771D03. // 'DOMAIN' (String): Domain full name + // 'OWNER' (String): Owner handle + // --> CXM_ACK with 'DOMAIN_HANDLE' (String): Created handle for this domain + // ************** MF INSTALLER SERVICE ************** + +public define Word32 _CXM_INSTALLER_SERVICE_MSG_BASIS= 0x33772000. +public define Word32 _CXM_INSTALLER_SERVICE_ID = 0x33772001. +public define Word32 _CXM_INSTALLER_REGISTER_APP_ID = 0x33772002. +public define Word32 _CXM_INSTALLER_GET_NEW_SERIALS = 0x33772003. +public define Word32 _CXM_INSTALLER_CONFIRM_SERIALS_PUBLICATION = 0x33772004. +public define Word32 _CXM_INSTALLER_GET_MODELS = 0x33772005. // returns the MF models list + +// ************************************************* +// ************* MF API ************* + +// ************* ACCOUNTS SERVICE ************* + +public define Word32 _CXM_ACCOUNT_SERVICE_MSG_BASIS = 0x33772100. + +// ************* MAILINGS SERVICE ************* + +public define Word32 _CXM_MAILING_SERVICE_MSG_BASIS = 0x33772200. +public define Word32 _CXM_MAILING_SERVICE_ID = 0x33772200. // same as MSG_BASIS + +public define Word32 _CXM_MAILING_CREATE_CONTACT = 0x33772201. +public define Word32 _CXM_MAILING_UPDATE_CONTACT = 0x33772202. +public define Word32 _CXM_MAILING_DELETE_CONTACT = 0x33772203. + +public define Word32 _CXM_MAILING_CREATE_MAILING = 0x33772211. +public define Word32 _CXM_MAILING_UPDATE_MAILING = 0x33772212. +public define Word32 _CXM_MAILING_DELETE_MAILING = 0x33772213. + +public define Word32 _CXM_MAILING_ADD_CONTACT_TO_MAILING = 0x33772221. +public define Word32 _CXM_MAILING_REMOVE_CONTACT_FROM_MAILING = 0x33772222. + + +// ************* DIRECTORY SERVICE ************* + +public define Word32 _CXM_DIRECTORY_SERVICE_MSG_BASIS = 0x33772300. + +// ************* BACKUP SERVICE ************* + +public define Word32 _CXM_BACKUP_SERVICE_MSG_BASIS = 0x33772400. +public define Word32 _CXM_BACKUP_SERVICE_ID = 0x33772401. +public define Word32 _CXM_BACKUP_GET_STATUS = 0x33772402. /// Get backup status for a given MF (can subscribe, subscribed, subscription end date...) +public define Word32 _CXM_BACKUP_STARTING_BACKUP = 0x33772403. /// Notify BackupService that backup process is starting +public define Word32 _CXM_BACKUP_FINISHING_BACKUP = 0x33772404. /// Notify BackupService that backup process is finishing +public define Word32 _CXM_BACKUP_STARTING_RESTORE = 0x33772405. /// Notify BackupService that restore process is starting +public define Word32 _CXM_BACKUP_FINISHING_RESTORE = 0x33772406. /// Notify BackupService that restore process is finishing + +// ************* STATISTICS SERVICE ************* + +public define Word32 _CXM_STATS_SERVICE_MSG_BASIS = 0x33772500. + +// ************* SUPERVISER SERVICE ************* + +public define Word32 _CXM_SUPERVISER_SERVICE_MSG_BASIS = 0x33772600. +public define Word32 _CXM_SUPERVISER_SERVICE_ID = 0x33772600. +public define Word32 _CXM_SUPERVISER_GET_STATUS = 0x33772601. + +// ************* TEGAMIGAWA SERVICE ************* + +public define Word32 _CXM_TEGAMIGAWA_SERVICE_MSG_BASIS = 0x33772700. +public define Word32 _CXM_TEGAMIGAWA_SERVICE_ID = 0x33772700. +public define Word32 _CXM_TEGAMIGAWA_REGISTER_CLIENT = 0x33772701. + +// ************************************************* +// ************* KERO_PBX API ************* + +public define Word32 _CXM_KERO_PBX_MSG_BASIS = 0x33780000. // Ask Boxes to publish their informations diff --git a/web/CXM_making_a_web_site.anubis b/web/CXM_making_a_web_site.anubis index c025f64..15c50b8 100644 --- a/web/CXM_making_a_web_site.anubis +++ b/web/CXM_making_a_web_site.anubis @@ -1,4633 +1,4640 @@ - - - *Project* Anubis - - *Title* Making interactive Web sites. - - *Copyright* Copyright (c) Alain Prouté 2004-2005. - Copyright (c) Calexium 2007. - - - *Authors* Alain Prouté - David René - - *Revised* May 2007 - - - *Overview* - - In this file we propose simple tools for making well structured interactive and secured - web sites. - - - ----------------------------------- Table of Contents --------------------------------- - - * (1) Structure of a web site. - ** (1.1) Three sorts of data. - ** (1.2) How requests are handled. - ** (1.3) What web pages are made of. - ** (1.4) Actions. - ** (1.5) States. - - * (2) Carrying on. - ** (2.1) Describing your web sites. - ** (2.2) Directories on the server's disk. - ** (2.3) Starting your web sites. - - * (3) The HTML interface. - ** (3.1) Types used by the HTML interface. - ** (3.2) ``in form'' versus ``off form''. - ** (3.3) Defining your own style. - ** (3.4) Actioners and forms. - ** (3.5) Local popup. - - --------------------------------------------------------------------------------------- - - -read tools/basis.anubis -read tools/printable_tree.anubis -read system/string.anubis -read system/logger.anubis -read CXM_common.anubis -read CXM_multihost_http_server.anubis -read web/mime.anubis -read CXM_cookies.anubis - - - * (1) Structure of a web site. - - First of all we need to explain what a web site should be made of. Ideally, the - visitor (also called the 'client') should see the web site working as any other - interactive computer software. So, it should be clear that a 'session' (i.e. a visit - to the web site, including the consultation of several pages) is some kind of - conversation between the visitor and the web site, and that the web site should - maintain a 'current state' of this conversation. At each new request (click) from the - visitor, this state must be updated. This whole conversation is called a 'session' and - should not be confused with a single request. - - - - ** (1.1) Three sorts of data. - - All the data needed for putting a web site at work may be dispatched into three - categories: - - 1. Constant data (data that never change). These data may be hard coded into the - Anubis source files of the web site. - - 2. Permanent data (data which always exist independantly of the users connected to - the web site). These data are normally recorded into data bases. - - 3. Session data (data which depend on a particular visitor and which exist only - during the time he visits the web site). These data are stored into so-called - 'states'. - - - It is important to determine which data belongs to which category. This is part of your - design decisions. - - - - ** (1.2) How requests are handled. - - We want to separate the following two functionalities (which are used at each request - (click) during a single session): - - - computing the new state from the previous state and from the client request, and - updating the data base, - - - computing the page to be sent to the client from the new current state and from - the informations in the data base. - - - The next picture shows the structure we have in mind: - - - request +---------+ HTML page (with a hidden state name) - .-------------------| client |<--------------. - | .-----------------| | | - | | previous state +---------+ | - | | name (if any) | - | | | client side - ............................................................................ - | | | server side - | | | - | | .-------------------. | - | | | previous state | | - V V V | | - +---------------+ +---------------+ +--------------+ - | compute state | | server's disk | | compute page | - +---------------+ +---------------+ +--------------+ - ^ | | ^ ^ ^ ^ ^ - | | | | | | | | - | | `--------------------+--------------------' | | - | | new state | | | - read | `------------------------+--------------------' | - write | new state name | - update V | - +-----------+ | - | data base |--------------------------------------------' - +-----------+ read only - - - When the client begins a session, there is no previous state. In this case, a default - 'initial state' is used instead. - - The data base may be updated by 'compute state' box, but should not be update by the - 'compute page' box. The 'compute page' box should be allowed only to read the data - base. - - In this file, all the above stuff is defined, except the 'compute state' and 'compute - page' boxes. You just have to provide the function for computing a new state (compute - state) and the function for computing the page (compute page) from the new state. You - don't have to worry about state names, saving and retrieving states and the like. - - - - - - ** (1.3) What web pages are made of. - - What the client can see in his browser's window may be called a 'page'. Within a page, - we have several sorts of components: - - - 'local' components, i.e. all components which do not open a connection, like - texts, images, etc... possibly using JavaScript programmation, - - - 'actioners', which, when clicked upon, open a connection with our web site; they - may appear as links or buttons, etc... - - - 'foreign links', which when clicked upon, open a connection with another web site - (or ours eventually). - - Of course, what an actioner does is just ask our web site to perform an action. To that - end, the actioner essentially sends the name of the action to be performed. However, it - may be necessary to provide additional informations which may be seen as 'operands' of - the action. In order to attach operands to an action, HTML provides the notion of - 'form'. Indeed, a form contains essentially a set of input fields into which the client - may put values for the required operands of the action, and a submit button, which is - the actioner itself. Notice that a single form may contain several submit buttons, - which simply means that there are several distincts actions taking the same set of - operands. - - Restrictions must be put on the use of all theses gadgets. Indeed, for example, - putting a form within another form is officially meaningless in HTML, and the client's - browser may be seriously disturbed by this. In this file, we propose an interface to - the HTML language, which forbids such meaningless things, simply by imposing a strict - typing of HTML concepts. - - Each web site may be accessible through two communication channels: - - - a non secured channel (HTTP), - - a secured channel (HTTPS). - - Nevertheless, the whole thing should be considered as a single web site. For example, - you may have a secured page, obtained through HTTPS, containing public images obtained - through HTTP. An actioner in a non secured page may open a secured connection, and - conversely. - - Summarizing, a web page is made of local elements, foreign links and actioners. - Actioners receive operands from forms, and they also choose to communicate through the - non secured or through the secured channel. - - - - +-------------------+ - | page | - | | +---------------+ - | +--------------+ | | next page | - | | form | | | (non secured) | - | | +----------+ | | HTTP | | - | | | actioner |---------------------------->| | - | | +----------+ | | +---------------+ - | | | | - | | +----------+ | | +---------------+ - | | | actioner |---------------------------->| next page | - | | +----------+ | | HTTPS | (secured) | - | | | | | | - | +--------------+ | | | - | | +---------------+ - | | - +-------------------+ - - - Notice that actioners need no be necessarily put into forms. In that case, they work as - ordinary links, but they still may receive operands as we shall see. - - - - - ** (1.4) Actions. - - The client opens a new connection with our web site whenever he clicks on an - actioner. The result is that a request is sent, essentially made of a list of 'web - arguments'. Each web argument is a pair (name,value). One of these web arguments, the - 'action' web argument (whose name is "a"), determines the action to be performed. The - other web arguments (not including "s", used to identify the state) are the operands - for this action. - - Hence, the 'compute state' box in the picture above, splits naturally into as many - sub-boxes as there are actions. For this reason, we define the following type for - representing actions (where '$State' is the type representing session informations): - -public type Web_Action($State): - http_action (String name, // name of action - ($State) -> Bool allow, // true if action allowed - (HTTP_Info http_info, - List(Web_arg) web_args, // actually only 'operands' web arguments - $State state) -> $State do_it), - https_action (String name, // name of action - ($State) -> Bool allow, // true if action allowed - (HTTP_Info http_info, - List(Web_arg) web_args, // actually only 'operands' web arguments - $State state) -> $State do_it), - http_https_action (String name, - ($State) -> Bool allow, - (HTTP_Info http_info, - List(Web_arg) web_args, - $State state) -> $State do_it). - - 'http_action's are executed only under HTTP, and 'https_action's are executed only - under HTTPS. 'http_https_action's may be executed under both types of connections. - - Each action has a name, which is used to identify the action. Each action also has a - function 'allow' whose job is to verify that the action is allowed in the current - state, and a function 'do_it' for performing the action. The function 'do_it' receives - a lot of informations: - - - 'HTTP informations': - - the IP address of the client, - - the URI requested by the client (after redirection), - - the list of HTTP headers generated by the client's browser, - - the list of web arguments sent by the client (except "s" and "a"), - - the previous state (or the 'initial' or 'ticket expired' state if no previous - state can be found). - - In most cases, HTTP informations are not used. This is the reason why they are gathered - for simplicity into a unique datum of type 'HTTP_Info'. - -// For your convenience, we introduce the following simpler variants: -// -//public define Web_Action($State) -// http_action -// ( -// String name, -// $State -> Bool allow, -// (List(Web_arg),$State) -> $State do_it -// ) = -// http_action(name, -// (Maybe($State) ms) |-> if ms is -// { -// failure then true, -// success(s) then allow(s) -// }, -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is -// { -// failure then (failure, []), -// success(s2) then (success(do_it(l,s2)), []) -// }). -// -//public define Web_Action($State) -// https_action -// ( -// String name, -// $State -> Bool allow, -// (List(Web_arg),$State) -> $State do_it -// ) = -// https_action(name, -// (Maybe($State) ms) |-> if ms is -// { -// failure then true, -// success(s) then allow(s) -// }, -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is -// { -// failure then (failure, []), -// success(s2) then (success(do_it(l,s2)), []) -// }). -// -//public define Web_Action($State) -// http_https_action -// ( -// String name, -// $State -> Bool allow, -// (List(Web_arg),$State) -> $State do_it -// ) = -// http_https_action(name, -// (Maybe($State) ms) |-> if ms is -// { -// failure then true, -// success(s) then allow(s) -// }, -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is -// { -// failure then (failure, []), -// success(s2) then (success(do_it(l,s2)), []) -// }). - - - - When you define your web site, you must provide the list of all the actions of the - site. When a new state has been computed, a graphical representation of this state - must be sent to the client. To that end, you must provide a function (named below - 'compute_page') of type: - - $State -> HTTP_Answer - - where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML - pages. - -public type HTTP_Answer:... - - It should be clear that states and pages are deeply linked together. Indeed, we really - understand the page shown to the client as a representation of the current state of the - conversation between the client and the web site, but also containing informations - taken from the data bases. - - - - - - ** (1.5) States. - - Now, we explain how you can define the type (say 'State') to be used as an instance of - the type parameter '$State'. The following is just a suggestion. - - Each state determines a page (since 'compute_page' computes a page from a - state). However, some components of the state may be independant of the page. It may be - the case for example for the indication of the natural language used by the - client. Hence, a state should be made of (at least) two parts: - - - informations which are the same for all pages, - - informations which are particular to each page. - - For example, you could define: - - type Page: // one alternative per page, with particular informations - login(...), // in the components - main_page(...), - ...etc... - - Now, the type 'State' could be defined as follows: - - type State: - state(Language, // informations valid for all pages - ..., - Page). // informations particular to a page - - However, if you are making a secured web site within which clients should be identified - (by id and password), it may be a good idea to have two sorts of states, one for non - identified clients and one for identified clients. In this case, define the type - 'State' as follows (this is just a suggestion): - - type State: - non_identified(Language), - identified(String id, - Language, - Page). - - When a request arrives, check if the previous state is 'identified(...)' or - 'non_identified(...)', and don't provide access to certain pages to non identified - clients. This is required for security. - - Some more words on security. If your site needs to identify clients, define the - initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and - password of the client. If the id and password are correct, then change the state of - the client to 'identified(...)'. No other action should be able to do that. Now, be - confident that clients cannot forge states. The only information they have is the name - of a state, not the state itself which is never sent over the network, but only stored - on the server's disk. The name of the state is constructed using strong cryptographical - methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even - state names cannot be seen by a third party. So, if the system retrieves a previous - state of the form 'identified(...)', you can be confident that your client is well - identified, and you can send him confidential informations. - - States have a limited life time. It may happen that a client clicks on a button at a - time its state is out of date. In this case, this system considers that the new state - is a special state named 'ticket expired'. You must provide a function producing this - state when you describe your web site. The page corresponding to this state must just - inform the client that he/she waited a too long time before clicking on a button, and - has to restart (a new conversation) from the begining. - - - - * (2) Carrying on. - - ** (2.1) Describing your web sites. - - Before you may start your web site, you must describe it, i.e. produce a datum of the - opaque type 'Web_Site'. - -public type Web_Site:... - - Producing such a datum may be performed by: - -public define Web_Site - make_web_site_description - ( - List(String) common_names, // for example: ["www.our-business.com", - // "192.168.0.1"] - // the second one is just for testing - String site_directory, // where 'public' and other directories are - // located (should NOT end with '/') - String state_directory, - One -> One init, - (HTTP_Info, - List(Web_arg), - Bool is_https) -> $State initial_state, - ($State expired, - Maybe(String), - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_expired_state, - (Maybe(String), - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_lost_state, - List(Web_Action($State)) actions, - $State -> HTTP_Answer compute_page, - $State -> List(HTTP_header) additional_headers, - Int timeout, // seconds (todo: minutes) - Redirections redirections, - String charset, - List(String) journal_extensions, - List(String) journal_headers, - String authorization_secret, - List(MIME) known_mime_types, - (String action_name, - List(Web_arg) args)-> One before_send_file - ). - - - Explanations: - - 'common_names' is the list of names of the site (the name the browser must send as the - value of the 'Host' HTTP header in order to access the site must be in that list). Such - a name generally looks like this: - - www.somewhere.com - - If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of - the site must be exactly the same as the name on the certificate (which is precisely - called the 'common name' in the X.509 jargon). If the two names do not match, the site - will still work, but the transaction will not be transparent to the client. His browser - will complain that the name of the certificate does not match the name of the site, and - he will have to accept the certificate manually. - - 'site_directory' is the absolute path to the directory where the files needed by the - site are located. Usually this directory looks like: - - my_anubis/web_sites/www.somewhere.com - - However, this information is not computed from 'common_name', so that you can change - the common name (for example temporarily, for networking reasons) without loosing - access to the files. - - 'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state - whose graphical representation is a page explaining to the user that its 'ticket' (or - 'session information') has expired, and that he/she must close all popup windows and - start a new session. The arguments of the function contain the previous (expired) - state and all current informations concerning the user. This arguments may be useful - for example for producing the expiration message in the language chosen by the user. - You can also (and this may be much smarter) send a 'ticket prolongation page' - (including a new login for example), and resume the same conversation, since you have - all the pertinent informations at hand. In the case the ticket is definitely lost, the - second fonction 'ticket_lost_state' is used. - - Notice that despite the fact that the parameter $State is involved in the arguments of - the above function, the type 'Web_Site' does not depend on this parameter. This allows - to produce lists of web site descriptions, where each description may be constructed - with a different instance of $State. This is required because distinct sites must have - distinct types of session informations. This is made possible by the fact that the - type is obscure, and the constructor replaced by a function which assembles - 'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single - entity not depending on $State. You should have a look to the private part of this file - if you want more precisions about this programming technique. - - 'charset' is a string which will determine the character encoding to be used by the - browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252", - etc... - - 'before_send_file' is a function which is executed just before the HTTP server sends a - file. It gets an action name and the web arguments received with the request for that - file. Notice that this action name and these web arguments may be put into a - 'private_download' element, and will come back to the server at the time of the - download. - - - - ** (2.2) Directories on the server's disk. - - The description of your site contains the name of the directory within which the - required files are located. This may be for example: - - my_anubis/web_sites/www.our-business.com/ - - This is called the 'site directory' (for the given site). Within the site directory, - the following directories are created by this program: - - states - public - journal - private_download - upload_temporary - - The directory 'states' is used for storing states (session informations). Out of date - states are automatically removed after some time. - - The tree rooted at 'public' contains files that the server is allowed to send to the - clients. For security reasons, the server never sends a file which is not within the - tree whose root is this 'public' directory (except for the 'private download' mecanism; - see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis') - must have been recognized before the file may be sent. - - The directory 'journal' contains the jounal files. The roles of the remaining - directories 'private_download' and 'upload_temporary' is explained in - 'multihost_http_server.anubis', where you will also find further informations on - 'public' and 'journal'. - - - - - ** (2.3) Web servers parameters. - - The web servers have several parameters useful for administration. They are described - as follows: - - public type WebServersParameters: - wsparms(Var(Bool) shutdown_required, - - - - - ** (2.4) Starting your web sites. - - When you have described all your web sites (you may want to have several web sites, and - they are distinguished by their 'common name'), you may start them all together using - 'start_web_sites' below. This function returns a result of the following type: - -public type Start_Web_Sites_Result: - cannot_bind_to_port(Word32), - cannot_bind_to_port(Word32,Word32), - ok(Server http_server, - Server https_server). - - Indeed, it may happen that the system cannot bind (begin to listen) to one of the two - ports (or to both). The main reason is that another server is already listening on that - port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that - the 's' bit has not been set for 'user' and 'group' (there is not such problem under - Windows). Also notice that the Linux kernel may need a rather long time (up to several - minutes) before liberating a listening port. Now, if the system can bind to the two - ports, the pair of the two servers is returned. Two tools are useful for manipulating - servers: - - shutdown of type Server -> One - is_down of type Server -> Bool - - They are defined in 'predefined.anubis' (together with the type 'Server'). - - -public define Start_Web_Sites_Result - start_web_sites - ( - Word32 ip_address, // the IP address shared by the web sites - Word32 http_port, // usually: 80 - Word32 https_port, // usually: 443 - String ssl_certificate_common_name, - List(Web_Site) web_sites, // web sites to be started - (One) -> Bool shutdown_required - ). - - 'ip_address' is the IP address on which the two servers listen. If you put 0, the - servers listen on all the IP addresses of the machine. This may be useful if the - machine has several network interfaces. - - 'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec' - loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server - certificate. This is due to a problem of conception of SSL itself. See the book 'SSL - and TLS' by Eric Rescorla (at Addison Wesley) for more explanations. - - Notice that the number of servers is always 2, regardless of the number of web sites - you are starting. - - The dynamic variable 'shutdown_required' may be used to control the shutdown of the two - servers from within the web site (typically the administration part). The servers will - shutdown as soon as this variable contains 'true'. So you must provide a variable - containing 'false' otherwise your servers will not run. You may also use the primitive - 'must_restart' (see 'predefined.anubis') to control the restarting of your servers. - - - - - - - * (3) The HTML interface. - - We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination - of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more - reactive and attractive on the client side. - - - ** (3.1) Types used by the HTML interface. - - For easy reference, we gather below the definitions of all the types used by the HTML - interface, and we comment them immediately. - - -public type HTML_Size: - absolute(Int), // in pixels - percentage(Int). - - -public type Text_Option: - size(Int), // size of character font to use - font(String), // name of character font to use (such as "helvetica",...) - color(RGB), // color to be used for characters - italic, - oblique, - small_capitals, - bold, - underlined, - left_justified, - right_justified, - justified, // justified on both sides - line_through, - nowrap, - class(String), //CSS class - id(String), - style(String), - title(String), - attr(String, String). - -public define Text_Option - tooltip(String s) = title(s). - - A list of 'Text_Option' must be given with each text you want to put in your page. - - This indicate the way of reading text. -public type Reading_Way: - ltr, //the text is readable from "Left To Right" like english - rtl. //the text is readable from "Right To Left" like arabic - - -// Following types are define to prohib any arguments order error - -/** - * String value for 'id' attribut - */ -public type HtmlId: - htmlId(String id). - -/** - * String value for 'class' attribut - */ -public type HtmlClass: - htmlClass(String class). - -/** - * Name used in arguments list when form is submitted. - */ -public type WebArgName: - wan(String name). - -/** - * Value passed to arguments list when form is submitted (for RadioButton and CheckBox). - */ -public type WebArgValue: - wav(String value). - -/** - * Initial value of an input field. - */ -public type InitialValue: - init(String value). - -public define Printable_tree [HtmlId x . Printable_tree y] = str_pt(x.id, y). -public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y). -public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y). -public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y). -public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y). - - -public type HtmlEvents: - // Form element events - onchange, - onsubmit, - onreset, - onselect, - onblur, - onfocus, - // Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.) - onkeydown, - onkeypress, - onkeyup, - // Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.) - onclick, - ondblclick, - onmousedown, - onmousemove, - onmouseout, - onmouseover, - onmouseup. - -public type CoreAttrs: - id (String), - class (String), - style (String), - title (String), - lang (String), - dir (Reading_Way), - accesskey (Word8), - tabindex (Int), - attr (String, String), - event (HtmlEvents, String). - -public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false"). - -public type InputAttrs: - class (String), - style (String), - title (String), - lang (String), - dir (Reading_Way), - accesskey (Word8), - tabindex (Int), - attr (String, String), - event (HtmlEvents, String). - -public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false"). - -public define CoreAttrs - tooltip(String s) = title(s). -public define InputAttrs - tooltip(String s) = title(s). - -public type I18n: - lang (String), - dir (Reading_Way). - -//public type DIV_Option: -// id (String), -// class (String), -// style (String), -// tooltip (String), -// lang (String), -// dir (Reading_Way), -// attr (String, String), -// event (HtmlEvents, String). -// - - A list of 'DIV_Option' must be given with each DIV you want to put in your page. - -define String event_name - ( - HtmlEvents e - ) = - if e is - { - // Form element events - onchange then "onchange", - onsubmit then "onsubmit", - onreset then "onreset", - onselect then "onselect", - onblur then "onblur", - onfocus then "onfocus", - // Keyboard events - onkeydown then "onkeydown", - onkeypress then "onkeypress", - onkeyup then "onkeyup", - // Mouse events - onclick then "onclick", - ondblclick then "ondblclick", - onmousedown then "onmousedown", - onmousemove then "onmousemove", - onmouseout then "onmouseout", - onmouseover then "onmouseover", - onmouseup then "onmouseup" - }. - -public type Table_Option: - background_color(RGB), // applied to all cells in the table - background_image(String url), - border(Int width_of_outer_edge, // if not present, all values are 0 - Int width_of_top_of_relief, - Int width_of_inner_edge, - RGB border_color), - width(Int), // sets a minimal width for the table - percentage_width(Int), - attr(String name, String value), - class(String class_name). - - -public define Table_Option nude = border(0,0,0,rgb(0,0,0)). - - - A list of 'Table_Option' must be given with each table. - - -public type BackgroundOption: - repeat, // repeat the background in both directions - repeat_horizontal, // repeat the background only horizontally - repeat_vertical, // repeat the background only verticall - no_repeat, // don't repeat the background - center. - - -public type Cell_Option: - core_attrs(List(CoreAttrs)), - left, // put the content of the cell on the left - h_center, // center the content of the cell horizontally - right, // put the content of the cell on the right - top, // put the content of the cell upwards - v_center, // center the content of tye cell vertically, - bottom, // put the content of the cell downwards - base_line, // align the content vertically according to base lines - background_color(RGB), - background_image(String url, BackgroundOption), - width(Int), // sets a minimal width for the cell - percentage_width(Int), - height(Int), // sets a minimal height for the cell - columns(Int), // lets the cell span over several columns - rows(Int), // lets the cell span over several rows - nowrap, // do not allow text wrapping within the cell - class(String class_name). - - A list of 'Cell_Option' must be given with each cell and each row in a table. Options - given with a row apply to all the cells in the row, but are superseded by options given - with cells, which apply only to the cell they are given with. - - -public type HTML_Cell($T): - cell(List(Cell_Option) options, $T content). - -public type HTML_Header_Cell($T): - header_cell(List(Cell_Option) options, $T content). - - The parameter $T is later instantiated either to 'HTML_In_Form' or to 'HTML_Off_Form', - depending on where you put your table (within a form or not within a form). For your - convenience, we define the following particular case: - -public define HTML_Cell($T) - cell - ( - $T content - ) = - cell([],content). - -public define HTML_Header_Cell($T) - header_cell - ( - $T content - ) = - header_cell([],content). - - -public type HTML_Row($T): - row(List(Cell_Option) options, List(HTML_Cell($T)) cells). - -public type HTML_Header_Row($T): - empty, - header_row(List(Cell_Option) options, List(HTML_Header_Cell($T)) cells). - -public type HTML_Footer_Row($T): - empty, - footer_row(List(Cell_Option) options, List(HTML_Cell($T)) cells). - - Same remark as for 'HTML_Cell($T)'. We define several convenience functions: - -public define HTML_Row($T) - row - ( - List(HTML_Cell($T)) cells - ) = - row([],cells). - -public define HTML_Row($T) - row - ( - HTML_Cell($T) cell - ) = - row([],[cell]). - -public define HTML_Header_Row($T) - header_row - ( - List(HTML_Header_Cell($T)) cells - ) = - header_row([],cells). - -public define HTML_Header_Row($T) - header_row - ( - HTML_Header_Cell($T) cell - ) = - header_row([],[cell]). - -public type Actioner_Connection: - same, // use same type of connection as current page - http, // use non secured connection - https. // use secured connection - -public type Other_Window_Option: - resizable, // the new window may be resized by the client - scrollbars, // the new window has scrollbars - width(Int), // the new window has the specified width - height(Int). // the new window has the specified height - -public type Actioner_Target: - same, - same (String label), - other(String window_name, List(Other_Window_Option)). - -public type Actioner_Aspect: - link (List(Text_Option), String text, Maybe(String) name),// hypertext link - img_link (String img_url, String alt_text), - push_button (List(CoreAttrs),String text), - button (String url_off, String url_on), // rollover button - button (String url_off, String url_on, Int w, Int h), // idem with size - submit (List(CoreAttrs),String text), - immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices), - immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected). - - - -public type Actioner_Local_Action: - close_window. - - -public define Actioner_Aspect - link - ( - List(Text_Option) options, - String text - ) = - link(options, text, failure). - -public define Actioner_Aspect - link - ( - String text - ) = - link([], text, failure). - - -public define Actioner_Aspect - link - ( - List(Text_Option) options, - Int i - ) = - link(options,to_decimal(i), failure). - -public define Actioner_Aspect - link - ( - Int i - ) = - link([], i). - -public define Actioner_Aspect - button - ( - String url_img - ) = - button(url_img,url_img). - - Actioners are explained in details below. - - -public type TextAreaOption: - input_attrs(List(InputAttrs)), - disabled, - read_only, - wrap_lines. - -public type CSS_Style: - text_options(List(Text_Option)). - -public type CSS_File: - css_file(String file_name). - -public type JS_Attribute: - attr (String, String). - -public type JS_File: - js_file(String file_name, - List(JS_Attribute) attributes). - -public type Script: - script( String script_type, - String content). - -public define JS_File - js_file - ( - String file_name - ) = - js_file(file_name, []). - -public type HTML_Meta:... - -public type HTML_Off_Form:... - -public type HTML_Head_Tag: - meta(HTML_Meta), - title(String), - js(JS_File), - js_inline(Script), - css(CSS_File), - css_inline(String css_styles) /* Note: tags are not necessaries */ - . - - /* It contains - * - a List of HTML_Head_Tag representing necessaries head tags for the content. ex: jquery js files, js script, css specific styles, ... - * - a HTML_Off_Form representing the HTML code for the part of the page we want to display - */ -public type HTML_Partial_Content: - partial_content - ( - List(HTML_Head_Tag), - HTML_Off_Form - ) - . - -public define List(HTML_Head_Tag) - to_HTML_Head_Tag - ( - List(CSS_File) css_file_list - )= - map((CSS_File css_f) |-> css(css_f), css_file_list). - -public define List(HTML_Head_Tag) - to_HTML_Head_Tag - ( - List(JS_File) js_file_list - )= - map((JS_File js_f) |-> js(js_f), js_file_list). - -public type HTML_In_Form: - literal_pt (Printable_tree), - literal (String), - sequence (List(HTML_In_Form) items), - text (List(Text_Option), String the_text), - preformated (List(Text_Option), String), - paragraph (List(Text_Option), HTML_In_Form content), - image (List(CoreAttrs), String url, String alternate), - image (List(CoreAttrs), String url, String alternate, Int width, Int height), - table (List(Table_Option), HTML_Header_Row(HTML_In_Form), List(HTML_Row(HTML_In_Form)), HTML_Footer_Row(HTML_In_Form)), - center (HTML_In_Form), - mail_to (String email, HTML_In_Form element), - scroller (Int width, Int height, - Int content_width, Int content_height, - HTML_In_Form content), - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect, - String action_name, List((String,String)) extra_ops, - List(Actioner_Local_Action)), - foreign_link_new (Actioner_Target, Actioner_Aspect, String url), - foreign_link (List(Text_Option), String url), - foreign_link (List(Text_Option), String url, String name), - private_download (String abs_path, String name, String extra_ext, - Maybe((String,List((String,String)))) action), - text_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width), - text_input_ro (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width), - password_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width), - text_area (List(TextAreaOption), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width, Int height), - file_upload (List(InputAttrs), String label, HtmlId id, WebArgName name, Int width), - selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices), - selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices, InitialValue selected), - // List((String,String)) = List((code,name)) where : - // code is the web-arg value - // name appears in selector - selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices), - selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected), - radio_button (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), - radio_button_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), - check_box (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), - check_box_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), - div (List(CoreAttrs), HTML_In_Form content), - div_empty (List(CoreAttrs)), - hidden (HtmlId id, WebArgName name, InitialValue init). - - - 'HTML_In_Form' defines all the elements you may put within a form. We define a - convenience function: - -public define HTML_In_Form literal(Printable_tree t) = literal_pt(t). - -public define HTML_In_Form image(String url) = image([], url, url). - -public define HTML_In_Form image(String url, Int width, Int height) = image([], url, url, width, height). - -public define HTML_In_Form - foreign_link - ( - Int tsize, - String url, - String name - ) = - foreign_link([size(tsize)],url,name). - -public define HTML_In_Form - actioner - ( - Actioner_Connection conn, - Actioner_Target targ, - Actioner_Aspect asp, - String action_name, - List((String,String)) extra_ops - ) = - actioner(conn,targ,asp,action_name,extra_ops,[]). - -public define HTML_In_Form - actioner - ( - Actioner_Connection conn, - Actioner_Target targ, - Actioner_Aspect asp, - ) = - actioner(conn, targ, asp, "", [], []). - - -public define HTML_In_Form - text_area - ( - WebArgName name, - InitialValue init, - Int width, - Int height - ) = - text_area([], "", htmlId(""), name,init,width,height). - -public define HTML_In_Form - text_area - ( - List(TextAreaOption) options, - WebArgName name, - InitialValue init, - Int width, - Int height - ) = - text_area(options, "", htmlId(""), name,init,width,height). - -public define HTML_In_Form - table - ( - List(HTML_Row(HTML_In_Form)) rows - ) = - table([],empty,rows,empty). - -public define HTML_In_Form - table - ( - List(Table_Option) options, - List(HTML_Row(HTML_In_Form)) rows - ) = - table(options,empty,rows,empty). - -public define HTML_In_Form - table - ( - HTML_Header_Row(HTML_In_Form) h_row, - List(HTML_Row(HTML_In_Form)) rows - ) = - table([],h_row,rows,empty). - -public define HTML_In_Form - table - ( - List(Table_Option) options, - HTML_Header_Row(HTML_In_Form) h_row, - List(HTML_Row(HTML_In_Form)) rows - ) = - table(options,h_row,rows,empty). - -public define HTML_In_Form - private_download - ( - String abs_path, - String name, - String extra_ext - ) = - private_download(abs_path,name,extra_ext,failure). - -public define HTML_In_Form - private_download - ( - String abs_path, - String name, - String extra_ext, - String action_name, - List((String,String)) args - ) = - private_download(abs_path,name,extra_ext,success((action_name,args))). - -public define HTML_In_Form - text - ( - String s - ) = - text([],s). - -public define HTML_In_Form - radio_button (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) - = radio_button (options, label_text, htmlId(n.name), n, value, checked). - -public define HTML_In_Form - radio_button_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) - = radio_button_r (options, label_text, htmlId(n.name), n, value, checked). - -public define HTML_In_Form - check_box (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) - = check_box (options, label_text, htmlId(n.name), n, value, checked). - -public define HTML_In_Form - check_box_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) - = check_box_r (options, label_text, htmlId(n.name), n, value, checked). - -public define HTML_In_Form - file_upload (WebArgName name, Int width) - = file_upload([], "", htmlId(""), name, width). - -public define HTML_In_Form - hidden (WebArgName name, InitialValue init) - = if name is wan(web_name) then - hidden(htmlId(web_name), name, init). - -public type HTML_Body:... - -public type HTML_Off_Form: - literal_pt (Printable_tree), - literal (String), - sequence (List(HTML_Off_Form) items), - text (List(Text_Option), String the_text), - preformated (List(Text_Option), String), - paragraph (List(Text_Option), HTML_Off_Form content), - image (List(CoreAttrs), String url, String alternate), - image (List(CoreAttrs), String url, String alternate, Int width, Int height), - table (List(Table_Option), HTML_Header_Row(HTML_Off_Form), List(HTML_Row(HTML_Off_Form)), HTML_Footer_Row(HTML_Off_Form)), - center (HTML_Off_Form), - mail_to (String email, HTML_Off_Form element), - scroller (Int width, Int height, - Int content_width, Int content_height, - HTML_Off_Form content), - fixed_size (HTML_Size width, HTML_Size height, HTML_Off_Form content), - fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file), - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect, - String action_name, List((String,String)) extra_ops, - List(Actioner_Local_Action)), - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect, - String action_name, List((String,String)) extra_ops, - List(Actioner_Local_Action), String form_name), - foreign_link_new (Actioner_Target, Actioner_Aspect, String url), - foreign_link (List(Text_Option), String url), - foreign_link (List(Text_Option), String url, String name), - private_download (String abs_path, String name, String extra_ext, - Maybe((String,List((String,String)))) action), - label (String name), - form (HtmlId form_id, List(CoreAttrs), HTML_In_Form content), - form (HtmlId form_id, List(CoreAttrs), - String action_name, List((String,String)) extra_ops, - HTML_In_Form content), - div (List(CoreAttrs), HTML_Off_Form content), - div_empty (List(CoreAttrs)), - iframe (List(CoreAttrs), - List(CSS_Style) /*styles*/, - List(CSS_File) /*css_files*/, - List(JS_File) /*js_files*/, - HTML_Body /*body*/). - - 'HTML_Off_Form' defines all the elements you may put outside any form. - - -public define HTML_Off_Form image(String url) = image([], url, url). - -public define HTML_Off_Form image(String url, Int width, Int height) = image([], url, url, width, height). - -public define HTML_Off_Form - form - ( - String form_name, - List(CoreAttrs) options, - HTML_In_Form content - ) = - form(htmlId(form_name), options, content). - -public define HTML_Off_Form - form - ( - String form_name, - List(CoreAttrs) options, - String action_name, - List((String,String)) extra_ops, - HTML_In_Form content - ) = - form(htmlId(form_name), options, action_name, extra_ops, content). - - -public define HTML_Off_Form literal(Printable_tree t) = literal_pt(t). -public define HTML_Off_Form fixed_size(HTML_Size width, HTML_Size height, String name_of_HTML_file) - = fixed_size_2(width,height,name_of_HTML_file). - - -public define HTML_Off_Form - foreign_link - ( - Int tsize, - String url, - String name - ) = - foreign_link([size(tsize)],url,name). - - -public define HTML_Off_Form - actioner - ( - Actioner_Connection conn, - Actioner_Target targ, - Actioner_Aspect asp, - String action_name, - List((String,String)) extra_ops - ) = - actioner(conn,targ,asp,action_name,extra_ops,[]). - -public define HTML_Off_Form - table - ( - List(HTML_Row(HTML_Off_Form)) rows - ) = - table([],empty,rows,empty). - -public define HTML_Off_Form - table - ( - List(Table_Option) options, - List(HTML_Row(HTML_Off_Form)) rows - ) = - table(options,empty,rows,empty). - -public define HTML_Off_Form - table - ( - HTML_Header_Row(HTML_Off_Form) h_row, - List(HTML_Row(HTML_Off_Form)) rows - ) = - table([],h_row,rows,empty). - -public define HTML_Off_Form - table - ( - List(Table_Option) options, - HTML_Header_Row(HTML_Off_Form) h_row, - List(HTML_Row(HTML_Off_Form)) rows - ) = - table(options,h_row,rows,empty). - - We add two convenience functions for 'row'. The reason why we add two functions, one - for 'HTML_In_Form' and one for 'HTML_Off_Form', is that adding a schema with an - arbitrary '$T' creates too many ambiguities. This is due to the fact that, if we do so, - the arguments of the function do not refer to any of the types defined here. - -public define HTML_Row(HTML_In_Form) - row - ( - HTML_In_Form content - ) = - row([],[cell([],content)]). - -public define HTML_Row(HTML_Off_Form) - row - ( - HTML_Off_Form content - ) = - row([],[cell([],content)]). - - -public define HTML_Off_Form - private_download - ( - String abs_path, - String name, - String extra_ext - ) = - private_download(abs_path,name,extra_ext,failure). - - -public define HTML_Off_Form - private_download - ( - String abs_path, - String name, - String extra_ext, - String action_name, - List((String,String)) args - ) = - private_download(abs_path,name,extra_ext,success((action_name,args))). - -public define HTML_Off_Form - text - ( - List(Text_Option) lto, - Int i - ) = - text(lto,to_decimal(i)). - - -public define HTML_Off_Form - text - ( - Int i - ) = - text([],i). - -public define HTML_Off_Form - text - ( - String s - ) = - text([],s). - - - Cell a gap between two other cells : - -public define HTML_Cell(HTML_Off_Form) - width_gap - ( - Int w - ) = - cell([width(w)],text([],"")). - -public define HTML_Cell(HTML_In_Form) - width_gap - ( - Int w - ) = - cell([width(w)],text([],"")). - - - - Row a gap between two other rows : - -public define HTML_Row(HTML_Off_Form) - height_gap - ( - Int h - ) = - row([],[cell([height(h)],text([],""))]). - -public define HTML_Row(HTML_In_Form) - height_gap - ( - Int h - ) = - row([],[cell([height(h)],text([],""))]). - - - Notice that the two types have alternatives in common (same name, same arguments types, - up to the value of the parameter $T), which correspond to elements which may be put - anywhere in the page. - - - - -define String - format - ( - List(Text_Option) l - ). - - - - -define Printable_tree - format_css_styles - ( - List(CSS_Style) l - ) = - if l is - { - [ ] then [ ], - [h . t] then - [ if h is - { - text_options(tos) then - [" body, span, p { ", format(tos), " }\n" ] - } - . format_css_styles(t)] - }. - - - -public type HTML_Meta: - keywords (List(String)), - refresh (Actioner_Connection connection, - Actioner_Target target, - String action_name, - Int delay), // in seconds - refresh (String url, Int delay), // in seconds - meta (String name, String content), - http_equiv (String name, String content), - generic_meta (List((String,String))), - literal (String). - - Meta tags are put in the 'head' of the HTML page. - - -public type Body_Option: - core_attrs(List(CoreAttrs)), - background_color (RGB), - background_image (String url), - background_image (String url, List(BackgroundOption)). - -public type HTML_Body: - body(List(Body_Option) options, HTML_Off_Form content). - - -public type HTTP_Answer: - html_page (HTTP_Status /*http_status*/, - List(HTML_Head_Tag) /*html tags*/, - HTML_Body /*body*/), - html_page (HTTP_Status /*http_status*/, - String /*title*/, - List(HTML_Meta) /*meta_tags*/, - List(CSS_Style) /*styles*/, - List(CSS_File) /*css_files*/, - List(JS_File) /*js_files*/, - List(Script) /*script*/, - HTML_Body /*body*/), - plain_text (HTTP_Status /*http_status*/, - String /*text*/), - custom_text (HTTP_Status /*http_status*/, - String /*mime_type*/, - String /*content*/), - custom_binary(HTTP_Status /*http_status*/, - String /*mime_type*/, - ByteArray /*content*/, - List(HTTP_header)/*other headers*/), - custom_tree (HTTP_Status /*http_status*/, - String /*mime_type*/, - Printable_tree /*content*/), - http_raw (Printable_tree), - html_content (HTTP_Status /*http_status*/, - HTML_Off_Form). - - -public define HTTP_Answer - html_page - ( - String title, - List(HTML_Meta) metas, - HTML_Body body - ) = - html_page(http_ok, title,metas,[],[],[],[],body). - -public define HTTP_Answer - html_page - ( - String title, - List(HTML_Meta) metas, - List(CSS_Style) styles, - HTML_Body body - ) = - html_page(http_ok, title, metas, styles, [], [], [], body). - - 'HTTP_Answer' represents the final product of the construction of a web page. - - - - - *** (3.2) ``in form'' versus ``off form''. - - There is a variety of HTML elements: texts, buttons, links, forms, inputs, etc... Some - of them may have a content, which is yet another HTML element (or several). Hence, it - is meaningful to say that an element is 'within' another one. Now, putting any element - within any other one may be meaningless. For example, an input element must be put - within a form (otherwise, it is useless), and a from within another form has no precise - meaning (and is forbidden by the HTML specification). - - Actually, the main criterium is ``within a form or not within a form''. So, HTML - elements in a given page are separated into two categories: those who are within a - form, and the others. Nevertheless, there are elements which may belong to both - categories, like images and texts. We want to make use of the strong typing mecanism of - Anubis in order to forbid non meaningful placement of elements. - - The type 'HTML_In_Form' defines elements to be put within forms. Similarly, - 'HTML_Off_Form' defines elements not to be put within forms. Both types are recursive, - and 'HTML_Off_Form' refers to 'HTML_In_Form' (via the 'form' alternative, of course), - but the two types are not cross recursive. This is the reason why it is impossible to - put a form within a form. In order to construct a web page, you essentially have to - produce a datum of type 'HTML_Off_Form' (maybe containing data of type 'HTML_In_Form'). - - In practice, you don't have to worry so much about these two types, because elements - which may be put anywhere are constructed for both types by functions with the same - name and the same arguments. Hence, for both types, you just write the same thing. You - are warned by the compiler only when you try to put an element at a place it is not - allowed. - - - - *** (3.3) Defining your own style. - - We provide generic tools for constructing HTML elements. However, your web site needs - to have a ``style''. - - To that end, you need to write down a set of ``styling functions'', using the tools - defined here. These styling functions allow the introduction of your colors and other - visual characteristics into the constructed elements once and for all. For example, you - may want all your texts to be rendered in the ``Helvetica'' font, in size 14 and using - some 'text_color'. You may write something like this: - - define RGB text_color = rgb(10,40,40). - - define HTML_Off_Form - text - ( - String the_text - ) = - text([font("helvetica"),size(14),color(text_color)], - the_text). - - (and the same one for type 'HTML_In_Form') so that in order to put a piece of text in a - page, you just write: - - text("... some text ...") - - and you don't have to provide the font, size and color for each text. If you want to - have several styles of text presentation, you just write several sets of such - convenience functions. This also suggests a trick. You may want for example different - colors for 'in form' texts and 'off form' texts. This may be achieved automatically by - defining two functions as above, with the same name and same argument type, but - returning either a 'HTML_In_Form' or a 'HTML_Off_Form'. - - If this preliminary work is well done, you will not waste your time later when you - concentrate on the actual informational content of your pages. - - This general principle should be applied to all sorts of elements. This is the best - thing to do in order to separate the functions defining the visual style from the - functions defining the informational content itself, so that changing the style without - changing the content becomes easy. This is also the best way for having a clean and - easily readable source for your web site. - - - - - - *** (3.4) Actioners and forms. - - We have gathered several notions from HTML into that of an 'actioner'. An actioner is - an HTML element which opens a connection to our server when clicked upon. Actioners may - have different visual aspects. They may look like hypertext links or like buttons - (rollovers), or even like selectors (with immediate action). In any case, their - behavior is the same: they open a connection to our server, and send a set of 'web - arguments', i.e. pairs 'name=value'. Among these web arguments, one of them denotes - the action to be performed, and the others should be considered as operands for this - action. Actually, the precise behavior of the actioner has several variants. - - The connection with the server may be secured (HTTPS) or non secured (HTTP). See the - type 'Actioner_Connection' above. - - You must also choose where the answer must be rendered. This may be in the same window - or in another window (or frame). If it is in another window, the name of that window - must be given. If the window does not exist, the browser will create it. Optionally, - you may give the dimensions of the new window and other characteristics. See the type - 'Actioner_Target' above. - - The actioner also has a visual aspect. See the type 'Actioner_Aspect' above. In the - case of a rollover button, you provide the URLs of two images (of the same size) - representing the button: - - url_off: to be used when the mouse is not over the button, - url_on: to be used when the mouse is over the button. - - You can also create rollover buttons without creating images. Just use the second - alternative named 'button'. The server creates the images automatically. - - The purpose of forms is just to give operands to actioners. If the actioner is placed - within a form, all the input elements which are within this form provide operands to - the actioner (except sometimes when they are not set by the client). If it is not put - within a form, the actioner gets no operand, except if the name of a form is explicitly - given, in which case the actioner gets all the inputs from that form as - operands. Furthermore, you may want to give extra operands to the actioner. This may be - useful for separating families of actioners with the same action name. Extra operands - 'name=value' must be given in the form of pairs '(name,value)'. - - Notice that the name of a form may be used by an actioner which is off the form, so as - to get the operands provided by this form. Also notice that several actioners may refer - to the same form, being either in the form, or referring to the form from the - outside. These actioners simply get the same set of operands, even if they correspond - to distinct actions. - - Input elements may be put only within a form. - - - - *** (3.5) Local popup. - - This element looks like a link or a rollover button. When this button is clicked upon, - a 'popup window' appears. Actually, this popup window is just a layer in the same HTML - page, which becomes suddenly visible. It is realized with a '
' HTML tag. In - particular, clicking on the button does not open any connection. This is why it is - called 'local'. The arguments have the following roles: - - Actioner_Aspect aspect of the button (same semantics as for actioners) - content content of the popup window - x, y, position of the popup window on the HTML page (not relative - to the button but to the page itself) - title title of the popup window - color color of the title bar and close button in the popup window. - A lightened version of this color is used for the background - of the popup window. - width width of the title bar - - - - - - --- That's all for the public part ! -------------------------------------------------- - - - - - - ----------------------------------- Table of Contents --------------------------------- - - *** [1] States. - *** [1.1] Saving and retrieving states. - *** [1.2] Deleting out of date states. - - *** [2] Tools. - *** [2.1] Directories. - *** [2.2] Secondary documents. - - *** [3] Managing web arguments. - *** [3.1] Prefixing web arguments names. - *** [3.2] Separating web arguments. - *** [3.3] Applying an action. - - *** [4] Web site descriptions and the 'awp handlers'. - *** [4.1] The type 'Web_Site'. - *** [4.2] Making a web site description. - *** [4.3] Starting the servers. - - *** [5] HTML Formating. - *** [5.1] The type 'HTML_Any($T)'. - *** [5.2] Formating a color. - *** [5.3] Creating buttons. - *** [5.4] Formating an actioner. - *** [5.5] Formating a private download link. - *** [5.6] Formating rows and cells in a table. - *** [5.7] Formating elements which may be put anywhere. - *** [5.8] Formating 'in form' elements. - *** [5.9] Formating 'off form' elements. - *** [5.10] Formating meta-tags. - - --------------------------------------------------------------------------------------- - - - - -public define String - doctype_w3c_header - = - "\n". - -public define String - html_header - = - "\n". - - - *** [1] States. - - We have to define functions for saving a state, retrieving a state, deleting out of - date states. We need one such function per web site. The types of the first two - functions depend on the parameter $State. This is not the case of the third one. The - fact that the instance of $State is variable from one web sites to the other implies - rather subtle manipulations using full functionality. - - - *** [1.1] Saving and retrieving states. - - Each state is saved into a file on the server's disk (in the directory represented by - the symbol 'state_directory', which is 'my_anubis/web_sites/common_name/states'). The - state is saved together with a time stamp whose value is obtained by adding the current - time to the given timeout for states. The state receives a name obtained by hashing - (using sha1) the content of the file itself, and then encoding the hash with - 'web_arg_encode'. The name of the file into which the state is saved is the - concatenation of "s" and the name of the state. - -read CXM_web_arg_encode.anubis - - The tool below constructs the function which is able to save a state on the server's - disk. - -define ($State s) -> String // the function constructed returns the name of the state - make_save_state_function - ( - Int timeout, - String state_directory - ) = - ($State s) |-> - with time_stamp = now+timeout, - to_be_saved = (time_stamp,s), - state_name = web_arg_encode(sha1(s)), - if save(to_be_saved,state_directory+"/s"+state_name) is ok - then state_name - else (print("Cannot create state file in '"+state_directory+"'.\n"); ""). - - - When a request arrives, we need to retrieve the previous state from the server's - disk. We receive the name of that state. If the state is out of date, the state file is - kept 3 days, and then deleted. - -type PreviousState($State): - not_found, // cannot retrieve the previous state - out_of_date($State), // the previous state is out of date - still_valid($State). // the previous state is still valid - -define (String state_name) -> PreviousState($State) - make_retrieve_state_function - ( - String state_directory - ) = - (String state_name) |-> - with file_path = state_directory+"/s"+state_name, - if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d) - then ( - if d is (time_stamp,s) then - 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. - - - - *** [1.2] Deleting out of date states. - - We also need to delete states which are out of date and which will never be deleted by - the above method. This may be performed by a machine doing this periodically (say once - per states life time period). - -define (List(String) file_names) -> One - make_delete_out_of_date_states_function - ( - Maybe($State) dummy, - String state_directory - ) = - (List(String) file_names) |-df-> - if file_names is - { - [ ] then unique, - [h . t] then - with file_path = state_directory+"/"+h, - if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d) - then ( - if d is (time_stamp,data) then - if time_stamp < now - then (forget(remove(file_path)); df(t)) - else df(t) - ) - else (forget(remove(file_path)); df(t)) - }. - - - The 'labelled arrow' |-df-> is documented in 'documentation/en/anubis_doc.txt'. - - Note: The argument 'dummy' (of type Maybe($State)) is not used in the body of the - function (hence its name). Nevertheless, it is required. Indeed, the Anubis compiler - does not accept a parameter in the body of a function (here the parameter is required - by the use of 'retrieve') if this parameter does not appear in the type of the - function. This is because this would create ambiguities that no explicit typing may - ever resolve. If you put a double slash in front of the declaration of 'dummy' above, - and if you compile this file, you will get a message like this one: - - Error in 'making_a_web_site.anubis', line 1300, column 7: - A definition may not contain parameters which are not present - in the declaration part (hidden parameters): - $State - - The type of the function constructed by 'make_delete_out_of_date_states_function' is - independant of the parameter $State. This is important because this allows to create - the list of such functions for all web sites. From this list, it is possible to call - the functions one after the other, so deleting out of date states for all web - sites. Actually, the next function receives a list of pairs (state_directory,function), - one for each web site. - -define One - delete_out_of_date_states // for all web sites - ( - List((String, List(String) -> One)) directories_and_functions - ) = - if directories_and_functions is - { - [ ] then unique, - [h . t] then if h is (state_directory,function) then - function(directory_list(state_directory,"s*")); - delete_out_of_date_states(t) - }. - - - The above function must be called periodically in a separate virtual machine. The - period we have choosen is (rather logically) the life time of states itself. This may - be achieved by an 'infinite' loop, using a 'sleep(timeout)'. However, the loop must not - be really infinite, because the servers may be shutdown. Hence, our loop must test - (rather frequently; say every second) if the servers are down. If they are, the loop - must be exited. - -define One - delete_states_loop - ( - List((String,List(String) -> One)) directories_and_functions, - Int timeout, - Int next_time, - Server http_server, - Server https_server, - (One) -> Bool shutdown_required - ) = - if shutdown_required(unique) - then (shutdown(http_server); shutdown(https_server)) - else unique; - if (is_down(http_server) & is_down(https_server)) - then unique - else if now > next_time - then - ( - delete_out_of_date_states(directories_and_functions); - delete_states_loop(directories_and_functions, - timeout, - now+timeout, - http_server, - https_server, - shutdown_required) - ) - else - ( - sleep(1000); // sleep just one second and try again - delete_states_loop(directories_and_functions, - timeout, - next_time, - http_server, - https_server, - shutdown_required) - ). - - The above loop must be run in a separate virtual machine. This will be done just after - the two servers are started. - - - - - - *** [2] Tools. - - *** [2.1] Directories. - - We need a tool for creating directories (if needed). - - (This tool has been moved to 'tools/basis.anubis'). - - - - - *** [2.2] Secondary documents. - - Some HTML elements (like '', '') cannot receive their content directly - from the current document, but only through an URL. For this reason, we implement a - mecanism for creating secondary documents on the fly. To that end we use the 'private - download' mecanism. - - A secondary document is formated by the same functions as the main document itself. The - next function takes an 'off form' element, creates the file containing the secondary - document in HTML format, and returns the URL at which the document will be available. - -define String - create_secondary_document - ( - String sd, // site directory - String as, // authorization_secret - String sn, // state name - $T -> Printable_tree format_element, - $T content, - HTML_Size width - ) = - with private_download_directory = sd+"/private_download", - hash = web_arg_encode(sha1(content)), - file_content = (Printable_tree) - [doctype_w3c_header, - "
", - format_element(content), - "
" - ], - file_name = "sd"+hash+".html", - file_path = private_download_directory+"/"+file_name, - if write_to_file(file_path,file_content) is - { - cannot_open_file then print("Cannot open file '"+file_path+"'.\n"); "", - write_error(n) then print("Error writing file '"+file_path+"'.\n"); "", - ok then file_name+"?zauth="+ - make_authorization(sd,as,private_download_directory+"/"+file_name) - }. - - - - - *** [2.3] Generating unique ids. - - In order to uniquely name object for JavaScript we generate unique ids from a counter. - -define Int - new_idnum - ( - Var(Int) ic_v // 'idnum' counter variable - ) = - protect - with result = *ic_v+1, - ic_v <- result; - result. - - - - - - - *** [3] Managing web arguments. - - Web arguments are those pairs 'name=value' which are transmitted through the HTTP - protocol. We need precise naming conventions for these web arguments. - - - - *** [3.1] Prefixing web arguments names. - - CR 2008-07-08 Prefixing Removed - - - - *** [3.2] Separating web arguments. - - When a new request arrives, we need to separate the web arguments, that is to say: - - - find the value of "s", and recover the corresponding state, - - find the value of "a", which is the name of the action to be performed, - - get the list of all the remaining web arguments (operands of the action). - - We must also determine if the previous state may be recovered. If it is not the case - (either because the previous state name is invalid, or the previous state is out of - date), we must check if there is an action name. Indeed, the presence of an action name - indicates that the user has clicked on one of our buttons or links. If on the contrary - there is no action name the user has just entered our address in his browser. In this - last case, we must send the first page of our site (maybe a 'login' page), but if there - is an action, we must send a page just saying that the session ticket has expired. If - the previous state is recovered and there is no action, the new state is the same as - the previous state. - - The result of the separation of the web arguments is of type: - -type Separated_Web_Args($State): - swa(PreviousState($State) previous_state, - Maybe(String) action_name, - List(Web_arg) operands). - - - - The next function constructs the function which separates the web arguments. - -define (List(Web_arg) lwa, HTTP_Info info) -> Separated_Web_Args($State) - make_separate_web_args_function - ( - String state_directory, - String -> PreviousState($State) retrieve_state, - String website_name - ) = - (List(Web_arg) lwa, HTTP_Info info) |-swaf-> - if lwa is - { - [ ] then - // - // no web arg found => no previous state and no action - // - if find_cookie("state_"+website_name, server_get_cookies(http_headers(info))) is - { - failure then swa(not_found,failure,[]), - success(cookie) then swa(retrieve_state(value(cookie)),failure,[]) - }, - - //swa(failure,failure,[]), - - [wa_1 . wa_others] then - // - // at least one web arg => - // separate other web args, and insert the first one as needed - // - if (Separated_Web_Args($State))swaf(wa_others, info) is - { - swa(ps1, // possible previous state - an1, // maybe an action name - op1) // operands so far - then - if wa_1 is - { - web_arg(n, value) then - with name = if substr(n,0,4) = "amp;" then substr(n, 4, length(n) - 4) else n, - if name = "a" then - swa(ps1,success(value),op1) - else if name = "t" then - swa(ps1,an1,[web_arg("target",value) . op1]) - else - swa(ps1,an1,[web_arg(name,value) . op1]), - - upload(n,v,t) then - swa(ps1,an1,[wa_1 . op1]) - } - } - }. - - - - - - - *** [3.3] Applying an action. - - When the web arguments are separated (and their names cleaned up from prefixes), we may - apply the action to the operands and the current state. We search for the action to be - applied in the list of actions. If no action is found, the new state is the same as - the previous state. Also, we deny the application of an HTTP action if the request - arrives through the HTTPS channel and conversely. - - -define ($State previous, - String action_name, - HTTP_Info http_info, - List(Web_arg) lwa, - Bool is_https) -> $State - make_apply_action_function - ( - List(Web_Action($State)) actions_list - ) = - with f = - ($State previous, - String action_name, - HTTP_Info http_info, - List(Web_arg) lwa, - Bool is_https, - List(Web_Action($State)) actions) |-f-> - //println("Looking for action ["+action_name+"]"); - if actions is - { - [ ] then print("action '"+action_name+ - "' not found.\n"); previous, - [ac1 . others] then if ac1 is - { - http_action(an,allow,do_it) then - if an = action_name - then if is_https - then (print("HTTP action '"+an+ - "' called through HTTPS (denied).\n"); - previous) - else if allow(previous) - then do_it(http_info,lwa,previous) - else previous - else f(previous,action_name,http_info,lwa,is_https,others), - - https_action(an,allow,do_it) then - if an = action_name - then if is_https - then if allow(previous) - then do_it(http_info,lwa,previous) - else previous - else (print("HTTPS action '"+an+ - "' called through HTTP (denied).\n"); - previous) - else f(previous,action_name,http_info,lwa,is_https,others), - - http_https_action(an,allow,do_it) then - if an = action_name - then - //println("Action ["+action_name+"] found"); - if allow(previous) - then do_it(http_info,lwa,previous) - else previous - else f(previous,action_name,http_info,lwa,is_https,others), - - } - }, - ($State previous, - String action_name, - HTTP_Info http_info, - List(Web_arg) lwa, - Bool is_https) |-> - f(previous, action_name, http_info, lwa, is_https, actions_list). - - - - - - - - - *** [4] Web site descriptions and the 'awp handlers'. - - *** [4.1] The type 'Web_Site'. - - The type 'Web_Site_Description' is defined in 'web/multihost_http_server.anubis'. We - need another one, because, we have some extra informations to record for each site. - -public type Web_Site: - web_site((Word32,Word32) -> Web_Site_Description description, - List(String) -> One delete_out_of_date). - - - - - *** [4.2] Making a web site description. - - Below is the function which creates a web site description. It first creates (if - needed) the directories for the site, then constructs the tool functions for the site, - and the site handler. Finally, it constructs the web site description. - - We gather common (constant) informations in the following type: - -public type CommonInfo: - info(String common_name, - Word32 http_port, - Word32 https_port, - String site_directory, - String authorization_secret - ). - - We need a forward declaration. - -public define Printable_tree - format - ( - CommonInfo cinfo, - String state_name, - List(HTTP_header) headers, - HTTP_Answer page, - Bool is_https, - String charset - ). - - -define Printable_tree - format - ( - HTML_Size s - ) = - if s is - { - absolute(x) then ["\"",x,"\""], - percentage(x) then ["\"",x,"%\""] - }. - -define List(HTTP_header) - make_state_cookie_headers - ( - String website_name, - String state_name - ) - = - [ - http_header("Set-Cookie", "state_"+website_name+"="+state_name) - ] - . - - public define Web_Site - make_web_site_description - ( - List(String) common_names, // for example: ["www.our-business.com", - // "192.168.0.1"] - // the second one is just for testing - String site_directory, // where 'public' and other directories are - // located (should NOT end with '/') - One -> One init, - (HTTP_Info, - List(Web_arg), - Bool is_https) -> $State initial_state, - ($State expired, - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_expired_state, - (HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_lost_state, - List(Web_Action($State)) actions, - $State -> HTTP_Answer compute_page, - $State -> List(HTTP_header) additional_headers, - Int timeout, // seconds (todo: minutes) - Redirections redirections, - String charset, - List(String) journal_extensions, - List(String) journal_headers, - String authorization_secret, - List(MIME) known_mime_types, - (String action_name, - List(Web_arg) args)-> One before_send_file - ). - - -public define Web_Site - make_web_site_description - ( - String website_name, - List(String) common_names, // for example: ["www.our-business.com"] - String site_directory, - String state_directory, - One -> One init, - (HTTP_Info, - List(Web_arg), - Bool is_https) -> $State initial_state, - ($State expired, - Maybe(String), - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_expired_state, - (Maybe(String), - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_lost_state, - List(Web_Action($State)) actions, - $State -> HTTP_Answer compute_page, - $State -> List(HTTP_header) additional_headers, - Int timeout, - Redirections redirections, - String charset, - List(String) journal_extensions, - List(String) journal_headers, - String secret, - List(MIME) known_mime_types, - (String action_name, - List(Web_arg) args) -> One before_send_file - //Bool using_state_cookies - ) = - 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_state = make_save_state_function(timeout, state_directory), - retrieve_state = make_retrieve_state_function(state_directory), - separate_web_args = make_separate_web_args_function(state_directory, retrieve_state, website_name), - 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) - if separate_web_args(lwa, http_info) is - { - swa(mb_previous_state, mb_action_name, operands) then - with new_state = if mb_previous_state is - { - not_found then - //println("previous state not found"); - if mb_action_name is - { - failure then initial_state(http_info, operands, is_https), - success(_) then - ticket_lost_state(mb_action_name, http_info,operands,is_https) - }, - - out_of_date(state) then - ticket_expired_state(state, mb_action_name, http_info,operands,is_https), - - still_valid(state) then - if mb_action_name is - { - failure then state, - success(action_name) then - apply_action(state,action_name,http_info,operands,is_https) - } - }, - //if state_and_headers is (session_ticket, mb_new_state, headers) then - with state_name = save_state(new_state), - //println("Cookie new STATE NAME "+state_name); - with cookie_headers = if mb_action_name is - { - failure then [], - success(action_name) then - if substr(action_name, 0, 5)="ajax_" then - [] - else - make_state_cookie_headers(website_name, state_name) - }, - - format(info(host_name, http_port, https_port, site_directory, secret), - state_name, - additional_headers(new_state) + cookie_headers, - compute_page(new_state), - is_https, - charset) - }), - // - // make the delete_out_of_date function - // - delete_out_of_date = - make_delete_out_of_date_states_function((Maybe($State))failure, - site_directory+"/states"), - // - // 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, - secret, - known_mime_types, - site_handler(http_port,https_port), - (HTTP_Info http_info, List(Web_arg) lwa) |-> 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). - -// Compatibility function for older websites -public define Web_Site - make_web_site_description - ( - List(String) common_names, // for example: ["www.our-business.com"] - String site_directory, - String state_directory, - One -> One init, - (HTTP_Info, - List(Web_arg), - Bool is_https) -> $State initial_state, - ($State expired, - Maybe(String), - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_expired_state, - (Maybe(String), - HTTP_Info, - List(Web_arg), - Bool is_https) -> $State ticket_lost_state, - List(Web_Action($State)) actions, - $State -> HTTP_Answer compute_page, - $State -> List(HTTP_header) additional_headers, - Int timeout, - Redirections redirections, - String charset, - List(String) journal_extensions, - List(String) journal_headers, - String secret, - List(MIME) known_mime_types, - (String action_name, - List(Web_arg) args) -> One before_send_file - //Bool using_state_cookies - ) - = - make_web_site_description("", common_names, site_directory, state_directory, init, initial_state, ticket_expired_state, ticket_lost_state, actions, compute_page, additional_headers, timeout, redirections, charset, journal_extensions, journal_headers, secret, known_mime_types, before_send_file) - . - - - - *** [4.3] Starting the servers. - -public define Start_Web_Sites_Result - start_web_sites - ( - Word32 ip_address, // the IP address shared by the web sites - Word32 http_port, // usually: 80 - Word32 https_port, // usually: 443 - String ssl_certificate_common_name, - List(Web_Site) web_sites, // web sites to be started - (One) -> Bool shutdown_required - ) = - with get_description = (Web_Site ws) |-> description(ws)(http_port,https_port), - with http_server_r = - start_http_server(ip_address,http_port, - map(get_description,web_sites), - load_denial_of_service_info), - with https_server_r = - start_https_server(ip_address,https_port, - ssl_certificate_common_name, - map(get_description,web_sites), - load_denial_of_service_info), - if http_server_r is ok(http_server) - then - ( - if https_server_r is ok(https_server) - then - ( - start_http_servers_tasks(map(get_description,web_sites), - [http_server,https_server], - 600); // period of 10 minutes - delegate - delete_states_loop( - map((Web_Site ws) |-> - (site_directory(description(ws)(http_port,https_port))+ - "/states",delete_out_of_date(ws)), - web_sites), - 3600*24*3, // keep out of date states 3 days - now, - http_server, - https_server, - shutdown_required), - ok(http_server,https_server) - ) - else cannot_bind_to_port(https_port) - ) - else - ( - if https_server_r is ok(https_server) - then cannot_bind_to_port(http_port) - else cannot_bind_to_port(http_port,https_port) - ). - - -public define One - start_web_sites - ( - Word32 ip_address, // the IP address shared by the web sites - Word32 http_port, // usually: 80 - Word32 https_port, // usually: 443 - String ssl_certificate_common_name, - List(Web_Site) web_sites, // web sites to be started - (One) -> Bool shutdown_required, - Logger log - ) = - if (Start_Web_Sites_Result)start_web_sites(ip_address, - http_port, - https_port, - ssl_certificate_common_name, - web_sites, - shutdown_required) is - { - cannot_bind_to_port(n) then logError(log, "Cannot bind to port: "+n), - cannot_bind_to_port(n,m) then logError(log, "Cannot bind to ports: "+n+", "+m), - ok(s1,s2) then logInfo(log, "Servers started on ports "+http_port+" (HTTP) and "+https_port+" (HTTPS).") - }. - - - - - - *** [5] HTML Formating. - - We need to translate HTML elements as defined above into actual HTML text. - - Actioners require special informations, which must be transmitted when needed by the - 'format' functions: - - - the 'common name', which is used for URLs, - - the HTTP/HTTPS port number, - - the 'state name', which must be transmitted when the actioner is clicked upon, - - the 'form name' (if any) to which the actioner refers. - - If the actioner is off form, and if it refers to a form, the name of that form is - already known by the actioner. On the contrary, if the actioner is 'in form', it refers - implicitly to the form containing it. The name of that form is transmitted to the - 'format' functions called from within the formating of that form. - - - - - *** [5.1] The type 'HTML_Any($T)'. - - The type 'HTML_Any($T)' gathers elements which may be put anywhere in the page. The - parameter $T becomes either 'HTML_Off_Form' or 'HTML_In_Form'. - -type HTML_Any($T): - any_text (List(Text_Option), String the_text), - any_preformated (List(Text_Option), String), - any_paragraph (List(Text_Option), $T content), - any_image (List(CoreAttrs), String url, String alternate), - any_image (List(CoreAttrs), String url, String alternate, Int width, Int height), - any_table (List(Table_Option), HTML_Header_Row($T), List(HTML_Row($T)), HTML_Footer_Row($T)), - any_center ($T), - any_mail_to (String email, $T element), - any_scroller (Int width, Int height, - Int content_width, Int content_height, - $T content), - any_fixed_size (HTML_Size width, HTML_Size height, $T content), - any_fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file), - any_actioner (Actioner_Connection, - Actioner_Target, - Actioner_Aspect, - String action_name, - List((String,String)) extra_ops, - List(Actioner_Local_Action), - Maybe(String) form_name), - any_foreign_link_new (Actioner_Target, Actioner_Aspect, String url), - any_foreign_link (List(Text_Option), String url), - any_foreign_link (List(Text_Option), String url, String name), - any_private_download (String abs_path, String name, String extra_ext, - Maybe((String,List((String,String))))), - any_div (List(CoreAttrs), $T element), - any_div_empty (List(CoreAttrs)), - any_coreattrs (List(CoreAttrs)). - - - - *** [5.2] Formating a color. - - RGB colors are formatted as '#rrggbb' where rr, gg and bb are two characters - hexadecimal values. - -define String - html_format - ( - RGB color - ) = - if color is rgb(r,g,b) then - "#" + to_hexa(r) - + to_hexa(g) - + to_hexa(b). - - - The following is a very arbitrary definition of the opposite color. The thing which is - important is that it is far from the original, so that characters in 'opposite' color - are clearly visible over the original. - -define RGB - opposite - ( - RGB color - ) = - if color is rgb(r,g,b) then - rgb(255-r, - 255-g, - 255-b). - - - - - *** [5.3] Creating buttons. - - We want to be able to create buttons in the form of a pair of images (rollovers) - automatically. We use the JPEG interface, because for the time being Anubis cannot - handle other kinds of images. - - - Computing printed text length. - - define Int - printed_text_width - ( - Word8 -> Int char_size, - List(Word8) l - ) = - if l is - { - [] then (Int) 0, - [h . t] then char_size(h) + 1+ printed_text_width(char_size,t) - }. - - define Int - printed_text_width - ( - SystemFont font, - String s - ) = - printed_text_width((Word8 c) |-> word8_to_int32(width(get_char_info(font,c))), - explode(s)). - - - - Converting RGB to RGBA. - -define RGBA - to_rgba - ( - RGB color - ) = - if color is rgb(r,g,b) then rgba(r,g,b,255). - - - Drawing a 'relief'. - - define One - draw_relief - ( - RGBAImage dest, - RGBA color, - Int contrast, - Int x, - Int y, - Int width, - Int height - ) = - with l = lighten(color,contrast), - d = darken(color,contrast), - draw_rectangle(dest,rect(x,y,x+width,y+1),l); - draw_rectangle(dest,rect(x,y+1,x+1,y+height),l); - draw_rectangle(dest,rect(x+width-1,y+1,x+width,y+height),d); - draw_rectangle(dest,rect(x+1,y+height-1,x+width-1,y+height),d). - - - Creating a button background. - - define RGBAImage - create_button_background - ( - RGBA color, - Int width, - Int height - ) = - with result = create_rgba_image(width,height,color), - draw_relief(result,color,100,0,0,width,height); - draw_relief(result,color,70,1,1,width-2,height-2); - draw_relief(result,color,55,2,2,width-4,height-4); - draw_relief(result,color,35,3,3,width-6,height-6); - draw_relief(result,color,20,4,4,width-8,height-8); - draw_relief(result,color,10,5,5,width-10,height-10); - draw_relief(result,color,5,6,6,width-12,height-12); - result. - - - Drawing the text over the background. - - define One - draw_button_text - ( - RGBAImage image, - String text, - Int text_index, - Int pixel_x, - Int y, - Rectangle clip, - RGBA color, - SystemFont font, - ) = - if nth(text_index,text) is - { - failure then unique, - success(c) then - with cw = draw_system_character(image,clip,pixel_x,y,font,word8_to_int32(c),color), - draw_button_text(image,text,text_index+1,pixel_x+cw+1,y,clip,color,font) - }. - - define One - draw_button_text - ( - RGBAImage image, - String text, - Int text_width, - RGBA light_color, - RGBA dark_color, - SystemFont font - ) = - with image_width = width(image), - image_height = height(image), - x_pos = (image_width-text_width)>>1, - clip = rect(0,0,image_width,image_height), - new_light_color = lighten(light_color,150), - new_dark_color = darken(dark_color,40), - draw_button_text(image, text, 0, x_pos+2, 16, clip, new_dark_color, font); - draw_button_text(image, text, 0, x_pos, 14, clip, new_light_color, font). - - - The next function creates the two images for a button. The information given is the - main color of the button, the text of the button and the minimal width (in pixels) of - the button. The function does not create the button if the images already exist. The - two images are stored in the directory 'site_directory/buttons'. The names of the files - are of the form: - - bxxxx_off.jpg - bxxxx_on.jpg - - where the prefix 'b' is to avoid leading '-' which may perturb UNIX commands (like - 'rm'), and where 'xxxx' is created from the given informations by the formula: - - xxxx = web_arg_encode(sha1((color,text,width))) - - Hence, distinct informations give distinct file names. - - - define String // returns xxxx - create_button_images - ( - String site_directory, - RGBA color, - String text, - Int width, - SystemFont font - ) = - with xxxx = web_arg_encode(sha1((color,text,width))), - buttons_dir = site_directory+"/public/buttons", - off_filepath = buttons_dir+"/b"+xxxx+"_off.jpg", - on_filepath = buttons_dir+"/b"+xxxx+"_on.jpg", - if file_exists(on_filepath) - then xxxx - else with - text_width = printed_text_width(font,text), - button_width = max(width,text_width+12), - button_height = (Int)20, - light_color = lighten(color,60), - very_light_color = lighten(light_color,30), - dark_color = darken(color,40), - background_off = - create_button_background(color,button_width,button_height), - background_on = - create_button_background(light_color,button_width,button_height), - - draw_button_text(background_off,text,text_width,very_light_color,dark_color,font); - draw_button_text(background_on, text,text_width,very_light_color,dark_color,font); - forget(write_image_to_JPEG_file(to_JPEG(background_off), - off_filepath, - 100)); - forget(write_image_to_JPEG_file(to_JPEG(background_on), - on_filepath, - 100)); - xxxx. - - - - - - *** [5.4] Formating an actioner. - - An actioner works as follows. Assume first that it refers to a form. When it is clicked - upon, the actioner puts (via 'onMouseDown') the URL into the 'action' attribute of the - form, and submits the form, using the JavaScript command 'form_name.submit()'. If the - actioner does not refer to a form, it fires the URL directly via 'href', because in - that case, the actioner is always an tag. - - The URL itself is composed using the connection sort (same, http or https), the common - name and port number (if needed), the state name, the action name, and the extra - operands, which are put into a query string. It may look like this: - - http://common_name:port/?s=state_name&a=action_name&oname=value... - - Each extra operand is a pair of strings: (name,value). It is formated as: - - &oname=value - - -define String - format_extra_operands - ( - List((String,String)) l - ) = - if l is - { - [ ] then "", - [h . t] then if h is (n,v) then - "&"+n+"="+v+format_extra_operands(t) - }. - - - It seams that the standard requires "&" instead of "&" ! - - In case the target is another window, we need to format the options for this window. - -define String - format - ( - List(Other_Window_Option) l - ) = - if l is - { - [ ] then "", - [h . t] then if h is - { - resizable then "resizable", - scrollbars then "scrollbars", - width(w) then "width="+w, - height(h2) then "height="+h2 - } + if t is [ ] then "" else (","+format(t)) - }. - - - - Formating choices for a "] - else - [s,""] - } - ], - button(url_off,url_on) then - [ if action is - { - url(u) then ["", - "\"",url_off,"\"", - "" - ], - - button(url_off,url_on,w,h) then - [ if action is - { - url(u) then ["", - "\"",url_off,"\"", - "" - ], - - submit(options, text) then - [ - if action is - { - url(u) then ["", - text, "" - ], - javascript(s,h) then - if action_name = "" then // special case where URL (so the action_name) is provided by the form itself - // so javascript isn't needed. This is the standard HMTL way. - [""] - else - [s,""] - } - ], - - immediate_selector(options,name,size,choices) then - [ if action is - { - url(u) then ["" - ], - immediate_selector(options,name,size,choices,selected) then - [ if action is - { - url(u) then ["" - ], - }. - - - - - - - *** [5.5] Formating a private download link. - - We get the absolute path of the file to be downloaded, and the name under which it - should appear to the client. The function 'format_private_download' creates an - hypertext link for downloading the file. The secured mecanism of private download is - used. This function is called by the function which formats HTML_Any($T) elements. - - -define Printable_tree - format_private_download - ( - CommonInfo cinfo, - String sn, // state name - String abs_path, // absolute file path on server - String name, // name of file as it appears in the browser - String extra, // extra extension - Maybe((String,List((String,String)))) action - - ) = - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then - with private_download_directory = site_directory+"/private_download", - with auth = make_authorization(site_directory,secret,abs_path), - [ - "", - name, - "" - ]. - - - - - *** [5.6] Formating rows and cells in a table. - -define Int - percent - ( - Int p - ) = - if p < 0 then 0 else if p > 100 then 100 else p. - - - - - Formating cell options. - - - -define String - format - ( - BackgroundOption o - ) = - if o is - { - repeat then "", - repeat_horizontal then "; background-repeat: repeat-x", - repeat_vertical then "; background-repeat: repeat-y", - no_repeat then "; background-repeat: no-repeat", - center then "; background-position: center top" - }. - -define String - format - ( - List(BackgroundOption) l - ) = - if l is - { - [ ] then "", - [h . t] then format(h)+format(t) - }. - - -define String - format - ( - List(Cell_Option) options - ) = - if options is - { - [ ] then "", - [h . t] then - if h is - { - core_attrs(core_attr_list) then format_attrs(core_attr_list), - left then " align=\"left\"", - h_center then " align=\"center\"", - right then " align=\"right\"", - top then " valign=\"top\"", - v_center then " valign=\"middle\"", - bottom then " valign=\"bottom\"", - base_line then " valign=\"baseline\"", - background_color(c) then " bgcolor=\""+html_format(c)+"\"", - background_image(n,o) then " style=\"background: url("+n+")"+format(o)+"\"", - width(w) then " width=\""+w+"\"", - percentage_width(n) then " width=\""+percent(n)+"%\"", - height(h2) then " height=\""+h2+"\"", - columns(n) then " colspan=\""+n+"\"", - rows(n) then " rowspan=\""+n+"\"", - nowrap then " nowrap", - class(class_name) then " class=\""+class_name+"\"" - } - + format(t) - }. - - - Normalizing a list of cell options (horizontal position must be specified; the default - is 'left'). - - Formating cells in a row. - -define Printable_tree - format - ( - List(HTML_Cell($T)) cells, - $T -> Printable_tree format_element - ) = - if cells is - { - [ ] then [ ], - [h . t] then if h is cell(options,element) then - ["", - format_element(element), - "" - . format(t,format_element)] - }. - -define Printable_tree - format - ( - List(HTML_Header_Cell($T)) cells, - $T -> Printable_tree format_element - ) = - if cells is - { - [ ] then [ ], - [h . t] then if h is header_cell(options,element) then - ["", - format_element(element), - "" - . format(t,format_element)] - }. - - Formating the rows in a table. - -define Printable_tree - format - ( - List(HTML_Row($T)) rows, - $T -> Printable_tree format_element, - ) = - if rows is - { - [ ] then [ ], - [h . t] then if h is row(options,cells) then - ["", - format(cells,format_element), - "\n" - . format(t,format_element)] - }. - -define Printable_tree - format - ( - HTML_Header_Row($T) row, - $T -> Printable_tree format_element - ) = - if row is - { - empty then [ ], - header_row(options,cells) then - [" ", - format(cells,format_element), - " \n" - ] - }. - -define Printable_tree - format - ( - HTML_Footer_Row($T) row, - $T -> Printable_tree format_element - ) = - if row is - { - empty then [ ], - footer_row(options,cells) then - [" ", - format(cells,format_element), - " \n" - ] - }. - -define Printable_tree - format1 - ( - List(TextAreaOption) l - ) = - if l is - { - [] then [], - [h . t] then if h is - { - input_attrs(input_attr_list) then [format_attrs(input_attr_list) . format1(t)], - disabled then [" disabled=\"disabled\" " . format1(t)] - read_only then [" readonly=\"readonly\" " . format1(t)] - wrap_lines then [" wrap=\"wrap\" " . format1(t)] - } - }. - -define Printable_tree - format - ( - List(TextAreaOption) l - ) = - if member(l,wrap_lines) - then format1(l) - else [" wrap=\"off\" " . format1(l)]. - - - *** [5.7] Formating elements which may be put anywhere. - - The function below involves the parameter $T which is later instantiated as - 'HTML_In_Form' or as 'HTML_Off_Form'. Now, since there are dictinct 'format' functions - for these two types, and because formating of tables requires recursive calls of such - functions, it is necessary to provide the 'format' function to be called recursively as - an argument. Putting naively a call to 'format' will not work, because the compiler - will look for a function able to format data of type $T (which is at that time distinct - from any other type, including our two types). Such a function does not exist. Hence - the function to be called for formating elements must be passed as a functional - argument (called 'format_element' below). Actually, what we pass is a function taking - a unique argument of type $T. Other informations (like the name of the state) are - already in the function by way of full functionality. - - - Formating text options. They are formated in CSS syntax, to be used within a - 'style=...'. - -define String - format - ( - List(Text_Option) l - ) = - if l is - { - [ ] then "", - [h . t] then if h is - { - size(n) then "font-size:"+n+"pt", - font(fn) then "font-family:"+fn, - color(c) then if c is rgb(r,g,b) then - "color:rgb("+to_decimal(r)+","+to_decimal(g)+","+to_decimal(b)+")", - italic then "font-style:italic", - oblique then "font-style:oblique", - small_capitals then "font-variant:small-caps", - bold then "font-weight:bold", - underlined then "text-decoration:underline", - left_justified then "text-align:left", - right_justified then "text-align:right", - justified then "text-align:justify", - line_through then "text-decoration:line-through", - nowrap then "white-space:nowrap", - class(class_name)then " class=\"" + class_name +"\"", - id(id_name) then " id=\"" + id_name +"\"", - style(style_string) then " style=\"" + style_string + "\"", - title(s) then " title=\"" + s +"\"" - attr(n,v) then " " + n + "=\"" + v +"\"" - } + if t is [ ] then "" else ("; "+format(t)) - }. - - - - Formating table options. - -define String - format - ( - List(Table_Option) l, - Bool border_seen - ) = - if l is - { - [ ] then if border_seen then "" else " border=\"0\" cellspacing=\"0\" cellpadding=\"0\"", - [h . t] then if h is - { - background_color(c) then " bgcolor=\""+html_format(c)+"\""+format(t,border_seen), - background_image(url) then " background="+url+format(t,border_seen), - border(o,top,i,c) then " border=\""+o+"\" cellspacing=\""+top+"\" cellpadding=\""+i+"\""+ - //" bordercolor="+format(c)+ - format(t,true), - width(w) then " width=\""+w+"\""+format(t,border_seen), - percentage_width(p) then " width=\""+percent(p)+"%\""+format(t,border_seen), - attr(name, value) then " " + name + "=\"" + value + "\"" +format(t,border_seen), - class(name) then " class=\""+name+"\"" - } - }. - - - - - -define Printable_tree - format_scroller - ( - String sn, - Int width, - Int height, - Int content_width, - Int content_height, - Int idnum, // identifying the scroller - $T content, - $T -> Printable_tree format_element - ) = - [ - "\n", - "", - "", - "", - "", - "", - "", - (if content_width > width then - [ - "", - "", - "", - ] else [ ]), - "", - "
", - "
", - "
", - format_element(content), - "
", - "
", - "
", - "", - "", - "", - "", - "", - "
\"sroll
\"scroll
", - "
", - "", - "", - "", - "", - "", - "", - "", - "
\"scroll\"scroll
", - "
" - ]. - - - -define Printable_tree - format - ( - Body_Option o - ) = - if o is - { - core_attrs(core_attr_list) then [" " + format_attrs(core_attr_list)], - background_color(c) then [" bgcolor=\"" , (String)html_format(c), "\""], - background_image(n) then [" background=", n], - background_image(n,o2) then [" style=\"background: url(",n,")",format(o2),"\""] - - }. - - - -define Printable_tree - format - ( - List(Body_Option) l - ) = - if l is - { - [ ] then [ ], - [h . t] then [format(h) . format(t)] - }. - -define Printable_tree - add_css_files - ( - List(CSS_File) l - ) = - if l is - { - [ ] then [ ], - [h . t] then - [ ["\n" ] - . add_css_files(t)] - }. - -define Printable_tree - add_js_files_attributes - ( - List(JS_Attribute) l - ) = - if l is - { - [ ] then [ ], - [h . t] then - if h is attr(name, value) then - [ " " + name + "=\"" + value + "\"" - . add_js_files_attributes(t)] - }. - - -define Printable_tree - add_js_files - ( - List(JS_File) l - ) = - if l is - { - [ ] then [ ], - [h . t] then - [ ["\n" - . add_js_files(t)] ] - }. - -define Printable_tree - add_script - ( - List(Script) l - ) = - if l is - { - [ ] then [ ], - [h . t] then [ "\n" . add_script(t) ] - }. - -define Printable_tree - add_css_styles - ( - List(CSS_Style) css_styles - ) = - - if css_styles is - { - [] then [], - [_ . _] then [ "\n" - ] - }. - - - // The function below formats a datum of type 'HTML_Any($T)'. - -define Printable_tree - format - ( - CommonInfo cinfo, - String sn, // state_name - Var(Int) ic_v, - HTML_Any($T) element, - $T -> Printable_tree format_element, // able to format a datum of type $T - Bool is_https, - ) = - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then - if element is - { - any_text(opts , t) then - if opts is - { - [] then [t], - [_ . _] then ["",t,""] - }, - any_preformated(opts,s) then - ["
",s,"
"], - //["
",s,"
"], - any_paragraph(opts,e) then - ["",format_element(e),"

\n"], - any_image(opts, url, alt) then - ["\"",alt,"\""], - any_image(opts, url, alt, w, h) then - ["\"",alt,"\""], - any_table(opts,h_row, rows, f_row) then - ["", - format(h_row, format_element), - "",format(rows,format_element),"", - format(f_row, format_element), - "\n"], - any_center(e) then - ["
",format_element(e),"
"], - any_mail_to(email,elem) then - ["",format_element(elem),""], - any_scroller(w,h,cw,ch,c) then - format_scroller(sn,w,h,cw,ch,new_idnum(ic_v),c,format_element), - any_fixed_size(w,h,c) then - with url = create_secondary_document(site_directory,secret,sn,format_element,c,w), - ["", - "secondary document", - ""], - any_fixed_size_2(w,h,fn) then - with url = fn+"?zauth="+make_authorization(site_directory,secret, - fn), - ["", - "secondary document", - ""], - any_actioner(c,t,a,an,eo,ja,fn) then - format_actioner(cinfo,sn,c,t,a,an,eo,ja,fn,is_https), - - any_foreign_link_new(target, aspect, url) then - format_foreign_link(target, aspect, url, is_https), - - any_foreign_link(options,url) then - [""], // IE7 doesn't support the form - any_foreign_link(options,url,name) then - ["",name,""], - any_private_download(url,name,extra_ext,action) then - format_private_download(cinfo,sn,url,name,extra_ext,action), - any_div(options, e) then - [format_div_option(options), format_element(e),"\n"], - any_div_empty(options) then - [format_div_option(options), "\n"], - any_coreattrs(attributs) then - [format_attrs(attributs)] - }. - - - - - // *** [5.8] Formating 'in form' elements. - - -define Printable_tree - maybe_label - ( - String label_text, - HtmlId id - ) = - if length(label_text) > 0 then [""] - else []. - - -define Printable_tree - format - ( - CommonInfo cinfo, - String fn, // form_name - String sn, // state_name - Var(Int) ic_v, // idnum counter variable - HTML_In_Form element, - Bool is_https, - ) = - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then - with format_element = (HTML_In_Form e) |-> format(cinfo,fn,sn,ic_v,e,is_https), - if element is - { - literal_pt(t) then t, - literal(t) then [t], - sequence(l) then flat(map(format_element,l)) - text(opts,t) then - format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https), - preformated(o,s) then - format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https), - paragraph(opts,t) then - format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https), - image(opts, url, alt) then - format(cinfo,sn,ic_v,any_image(opts, url, alt),format_element,is_https), - image(opts, url, alt, w, h) then - format(cinfo,sn,ic_v,any_image(opts, url, alt, w, h),format_element,is_https), - table(opts,header_row,rows,footer_row) then - format(cinfo,sn,ic_v,any_table(opts, header_row, rows, footer_row),format_element,is_https), - center(e) then - format(cinfo,sn,ic_v,any_center(e),format_element,is_https), - mail_to(a,e) then - format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https), - scroller(w,h,cw,ch,c) then - format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https), - actioner(c,t,a,an,eo,ja) then - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https), - - foreign_link_new(target, aspect, url) then - format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https), - - foreign_link(options,url) then - format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https), - foreign_link(options,url,name) then - format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https), - private_download(url,name,extra,action) then - format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https), - text_input(options, label_text, id, name, i, w) then - [ maybe_label(label_text, id), - ""], - text_input_ro(options, label_text, id, name,i,w) then - [ maybe_label(label_text, id), - ""], - password_input(options, label_text, id, name,i,w) then - [ maybe_label(label_text, id), - ""], - text_area(opts,label_text, id, n,i,w,h) then - [ maybe_label(label_text, id), ""], - file_upload(options, label, id, n, w) then - [ maybe_label(label, id), - ""], - selector(opts, label, id, n,s,cs) then - [ maybe_label(label, id), - ""], - selector(opts, label, id, n,s,cs,sd) then - [ maybe_label(label, id), - ""], - selector_c(opts, label, id, n,s,cs) then - [ maybe_label(label, id), - ""], - selector_c(opts, label, id, n,s,cs,sd) then - [ maybe_label(label, id), - ""], - - radio_button(options, label_text, id, n, v, c) then - [ maybe_label(label_text, id), - ""], - radio_button_r(options, label_text, id, n, v, c) then - [ "", - maybe_label(label_text, id)], - check_box(options, label_text, id, n, v, c) then - [ maybe_label(label_text, id), - ""] - check_box_r(options, label_text, id, n, v, c) then - [ "", - maybe_label(label_text, id)] - div(options, e) then - format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https), - div_empty(options) then - format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https), - hidden(id, name, value) then - [""], - - }. - - - - - - - *** [5.9] Formating 'off form' elements. - - The encryption type 'multipart/form-data' is required for a form containing an upload. - - -define Bool - contains_an_upload - ( - HTML_In_Form form_content - ). - -define Bool - contains_an_upload - ( - HTML_Row(HTML_In_Form) row - ) = - mapor(contains_an_upload, - map(content,cells(row))). - -define Bool - contains_an_upload - ( - HTML_Footer_Row(HTML_In_Form) row - ) = - if row is - { - empty then false, - footer_row(_, cells) then - mapor(contains_an_upload, - map(content,cells)) - }. - -define Bool - contains_an_upload - ( - HTML_In_Form form_content - ) = - if form_content is - { - literal_pt(t) then false, - literal(t) then false, - sequence(l) then mapor(contains_an_upload,l) - text(o,t) then false, - preformated(o,s) then false, - paragraph(o,t) then false, - image(o,u,a) then false, - image(o,u,a,w,h) then false, - table(o,_,rows,f_row) then if mapor(contains_an_upload,rows) then true - else contains_an_upload(f_row), - center(e) then contains_an_upload(e), - mail_to(m,e) then false, // 'e' may but should not contain an upload - scroller(w,h,cw,ch,e) then contains_an_upload(e), - actioner(c,t,a,an,eo,ja) then false, - foreign_link_new(_,_,_) then false, - foreign_link(o,u) then false, - foreign_link(o,u,n) then false, - private_download(p,n,e,a) then false, - text_input(o,lt,l,n,i,w) then false, - text_input_ro(o,lt,l,n,i,w) then false, - password_input(o,lt,l,n,i,w) then false, - text_area(o,lt,id,n,i,w,h) then false, - file_upload(o,l,i,n,w) then true, - selector(o,l,i,n,s,c) then false, - selector(o,l,i,n,s,c,p) then false, - selector_c(o,l,i,n,s,c) then false, - selector_c(o,l,i,n,s,c,p) then false, - radio_button(o,_,_,n,v,c) then false, - radio_button_r(o,_,_,n,v,c) then false, - check_box(o,_,_,n,v,c) then false, - check_box_r(o,_,_,n,v,c) then false, - div(o,c) then contains_an_upload(c), - div_empty(o) then false, - hidden(_,_,_) then false - }. - -define String - enctype - ( - HTML_In_Form form_content - ) = - if contains_an_upload(form_content) - then " enctype=\"multipart/form-data\"" - else "". - - - -define Printable_tree - format - ( - CommonInfo cinfo, - String sn, // state_name - Var(Int) ic_v, // 'idnum' counter variable - HTML_Off_Form element, - Bool is_https, - ) = - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then - with format_element = (HTML_Off_Form e) |-> format(cinfo,sn,ic_v,e,is_https), - if element is - { - literal_pt(t) then t, - literal(t) then [t], - sequence(l) then flat(map(format_element,l)), - text(opts,t) then - format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https), - preformated(o,s) then - format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https), - paragraph(opts,t) then - format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https), - image(opts,url,alt) then - format(cinfo,sn,ic_v,any_image(opts,url,alt),format_element,is_https), - image(opts,url,alt,w,h) then - format(cinfo,sn,ic_v,any_image(opts,url,alt,w,h),format_element,is_https), - table(opts,header_row, rows, footer_row) then - format(cinfo,sn,ic_v,any_table(opts,header_row, rows, footer_row),format_element,is_https), - center(e) then - format(cinfo,sn,ic_v,any_center(e),format_element,is_https), - mail_to(a,e) then - format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https), - scroller(w,h,cw,ch,c) then - format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https), - fixed_size(w,h,c) then - format(cinfo,sn,ic_v,any_fixed_size(w,h,c),format_element,is_https), - fixed_size_2(w,h,fn) then - format(cinfo,sn,ic_v,any_fixed_size_2(w,h,fn),format_element,is_https), - actioner(c,t,a,an,eo,ja) then - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,failure),format_element,is_https), - actioner(c,t,a,an,eo,ja,fn) then - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https), - foreign_link_new(target, aspect, url) then - format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https), - foreign_link(options,url) then - format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https), - foreign_link(options,url,name) then - format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https), - private_download(url,name,extra,action) then - format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https), - label(n) then [""], - form(fn,attributs, c) then - [ - "
", - // action is set dynamically by - // the actioner using JavaScript - if fn is htmlId(id) then - format(cinfo,id,sn,ic_v,c,is_https), - "
" - ] - form(fn,attributs, action_name, extra_ops, c) then - with url = make_actioner_url(cinfo, same, same, - sn, action_name, extra_ops, is_https), - [ - "
", -// " action=\"http", -// if is_https then "s" else "", -// "://",common_name,":",http_port,"/\">", - // action is set dynamically by - // the actioner using JavaScript - if fn is htmlId(id) then - format(cinfo,id,sn,ic_v,c,is_https), - "
" - ] - div(options, e) then - format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https), - div_empty(options) then - format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https), - iframe(options, css_styles, css_files, js_files, body) then - if body is body(body_options,element) then - [ "\n", - "\n", - "\n", - add_css_styles(css_styles), - add_css_files(css_files), - add_js_files(js_files), - "\n", - "\n", // format body options - format(cinfo,sn,ic_v,element,is_https), - "\n", - "\n", - "\n", - ], - - }. - - - - - *** [5.10] Formating meta-tags. - -define Printable_tree - format_keywords - ( - List(String) l - ) = - if l is - { - [] then [ ], - [h . t] then if t is [] - then [h] - else [h , ", " . format_keywords(t)] - }. - - -define Printable_tree - format - ( - CommonInfo cinfo, - String state_name, - HTML_Meta m, - Bool is_https - ) = - if m is - { - keywords(l) then ["\n"], - refresh(co,ta,an,delay) then - ["\n"], - refresh(url,delay) then - ["\n"], - meta(n,c) then ["\n"], - http_equiv(n,c) then ["\n"], - generic_meta(l) then [" if p is (n,v) then [n,"=\"",v,"\" "], - l)), - " />\n"], - literal(s) then [s] - }. - -define Printable_tree // c'est le nôtre et c'est meilleur - format - ( - HTML_Meta m, - ) = - if m is - { - keywords(l) then ["\n"], - refresh(co,ta,an,delay) then - [" "], // TODO - refresh(url,delay) then - ["\n"], - meta(n,c) then ["\n"], - http_equiv(n,c) then ["\n"], - generic_meta(l) then [" if p is (n,v) then [n,"=\"",v,"\" "], - l)), - " />\n"], - literal(s) then [s] - }. - - -define Printable_tree - format - ( - CommonInfo cinfo, - String state_name, - List(HTML_Meta) metas, - Bool is_https, - String charset - ) = - if metas is - { - [] then [format(cinfo,state_name,http_equiv("content-type", - "text/html; charset="+charset),is_https)], - [h . t] then [format(cinfo,state_name,h,is_https) - . format(cinfo,state_name,t,is_https,charset)] - }. - -define Printable_tree - _format_html_head - ( - List(HTML_Head_Tag) lwf, - Printable_tree so_far - ) - = - if lwf is - { - [] then reverse(so_far), - [ h . t] then - if h is - { - meta(meta) then - [format(meta) . _format_html_head(t, so_far)], - title(title) then - [""+title+"\n" . _format_html_head(t, so_far)], - js(jsf) then - [add_js_files([jsf]) . _format_html_head(t, so_far)], - js_inline(jsi) then - ["\n" . _format_html_head(t, so_far)], - css(cssf) then - ["\n" . _format_html_head(t, so_far)], - css_inline(cssi) then - ["\n" . _format_html_head(t, so_far)] - } - } - . - -public define Printable_tree - format_html_head - ( - List(HTML_Head_Tag) lwf, - String charset - ) - = - with lwf = (List(HTML_Head_Tag))[ meta(http_equiv("content-type", "text/html; charset="+charset)) . lwf], - if lwf is - { - [] then - [], - [ h . t] then - _format_html_head(lwf, []) - } - . - -define Printable_tree - format - ( - CommonInfo cinfo, - String state_name, - List(HTTP_header) additional_headers, - HTTP_Answer page, - Bool is_https, - String charset - ) = - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then - with ic_v = var((Int)0), - if page is - { - html_page(status, head_tags, body) then - if body is body(options,element) then - if format(status) is (status_string, status_headers) then - with answer_body = - [doctype_w3c_header, - html_header, - - "\n", format_html_head(head_tags, charset),"\n", - - "", // format body options - format(cinfo,state_name,ic_v,element,is_https), - "\n", - - ""], - [ "HTTP/1.1 " + status_string, crlf, - format_headers(standard_headers), - format_headers(standard_headers_for("text/html", length(answer_body), success(charset))), - format_headers(status_headers), - format_headers(additional_headers), - crlf - . answer_body - ] - - html_page(status, title, metas, css_styles, css_files, js_files, script, body) then - if body is body(options,element) then - if format(status) is (status_string, status_headers) then - with answer_body = - [ doctype_w3c_header, - html_header, - "\n", - add_css_styles(css_styles), - add_css_files(css_files), - add_js_files(js_files), - add_script(script), - "\n", - "\n", - "",title,"\n", // put title - format(cinfo,state_name,metas,is_https,charset), // format the metas - "\n", - "", // format body options - //"
", - format(cinfo,state_name,ic_v,element,is_https), - //"
", - "\n", - "" - ], - [ "HTTP/1.1 " + status_string, crlf, - format_headers(standard_headers), - format_headers(standard_headers_for("text/html", length(answer_body), success(charset))), - format_headers(status_headers), - format_headers(additional_headers), - crlf - . answer_body - ], - - plain_text (HTTP_Status status, String text) then - if format(status) is (status_string, status_headers) then - [ "HTTP/1.1 " + status_string, crlf, - format_headers(standard_headers), - format_headers(standard_headers_for("text/plain", length(text), success(charset))), - format_headers(status_headers), - format_headers(additional_headers), - crlf, - text . (Printable_tree)[] - ], - - custom_text(HTTP_Status status, String mime_type, String content) then - if format(status) is (status_string, status_headers) then - [ "HTTP/1.1 " + status_string, crlf, - format_headers(standard_headers), - format_headers(standard_headers_for(mime_type, length(content), success(charset))), - format_headers(status_headers), - format_headers(additional_headers), - crlf, - content . (Printable_tree)[] - ], - custom_binary(HTTP_Status status, String mime_type, ByteArray content, List(HTTP_header) other_headers) then - if format(status) is (status_string, status_headers) then - [ "HTTP/1.1 " + status_string, crlf, - format_headers(status_headers), - format_headers(standard_headers_for(mime_type, length(content), failure)), - format_headers(status_headers), - format_headers(other_headers), - format_headers(additional_headers), - crlf, - content . (Printable_tree)[] - ], - - custom_tree(HTTP_Status status, String mime_type, Printable_tree content) then - if format(status) is (status_string, status_headers) then - [ "HTTP/1.1 " + status_string, crlf, - format_headers(standard_headers), - format_headers(standard_headers_for(mime_type, length(content), success(charset))), - format_headers(status_headers), - format_headers(additional_headers), - crlf . - content - ], - - http_raw(Printable_tree content) then content, - - html_content(HTTP_Status status, HTML_Off_Form content_HTML) then - if format(status) is (status_string, status_headers) then - with content = format(cinfo, state_name, ic_v, content_HTML, is_https), - [ "HTTP/1.1 " + status_string, crlf, - format_headers(standard_headers), - format_headers(standard_headers_for("text/html", length(content), success(charset))), - format_headers(status_headers), - format_headers(additional_headers), - crlf . - content - ], - }. - + + + *Project* Anubis + + *Title* Making interactive Web sites. + + *Copyright* Copyright (c) Alain Prouté 2004-2005. + Copyright (c) Calexium 2007. + + + *Authors* Alain Prouté + David René + + *Revised* May 2007 + + + *Overview* + + In this file we propose simple tools for making well structured interactive and secured + web sites. + + + ----------------------------------- Table of Contents --------------------------------- + + * (1) Structure of a web site. + ** (1.1) Three sorts of data. + ** (1.2) How requests are handled. + ** (1.3) What web pages are made of. + ** (1.4) Actions. + ** (1.5) States. + + * (2) Carrying on. + ** (2.1) Describing your web sites. + ** (2.2) Directories on the server's disk. + ** (2.3) Starting your web sites. + + * (3) The HTML interface. + ** (3.1) Types used by the HTML interface. + ** (3.2) ``in form'' versus ``off form''. + ** (3.3) Defining your own style. + ** (3.4) Actioners and forms. + ** (3.5) Local popup. + + --------------------------------------------------------------------------------------- + + +read tools/basis.anubis +read tools/printable_tree.anubis +read system/string.anubis +read system/logger.anubis +read CXM_common.anubis +read CXM_multihost_http_server.anubis +read web/mime.anubis +read CXM_cookies.anubis + + + * (1) Structure of a web site. + + First of all we need to explain what a web site should be made of. Ideally, the + visitor (also called the 'client') should see the web site working as any other + interactive computer software. So, it should be clear that a 'session' (i.e. a visit + to the web site, including the consultation of several pages) is some kind of + conversation between the visitor and the web site, and that the web site should + maintain a 'current state' of this conversation. At each new request (click) from the + visitor, this state must be updated. This whole conversation is called a 'session' and + should not be confused with a single request. + + + + ** (1.1) Three sorts of data. + + All the data needed for putting a web site at work may be dispatched into three + categories: + + 1. Constant data (data that never change). These data may be hard coded into the + Anubis source files of the web site. + + 2. Permanent data (data which always exist independantly of the users connected to + the web site). These data are normally recorded into data bases. + + 3. Session data (data which depend on a particular visitor and which exist only + during the time he visits the web site). These data are stored into so-called + 'states'. + + + It is important to determine which data belongs to which category. This is part of your + design decisions. + + + + ** (1.2) How requests are handled. + + We want to separate the following two functionalities (which are used at each request + (click) during a single session): + + - computing the new state from the previous state and from the client request, and + updating the data base, + + - computing the page to be sent to the client from the new current state and from + the informations in the data base. + + + The next picture shows the structure we have in mind: + + + request +---------+ HTML page (with a hidden state name) + .-------------------| client |<--------------. + | .-----------------| | | + | | previous state +---------+ | + | | name (if any) | + | | | client side + ............................................................................ + | | | server side + | | | + | | .-------------------. | + | | | previous state | | + V V V | | + +---------------+ +---------------+ +--------------+ + | compute state | | server's disk | | compute page | + +---------------+ +---------------+ +--------------+ + ^ | | ^ ^ ^ ^ ^ + | | | | | | | | + | | `--------------------+--------------------' | | + | | new state | | | + read | `------------------------+--------------------' | + write | new state name | + update V | + +-----------+ | + | data base |--------------------------------------------' + +-----------+ read only + + + When the client begins a session, there is no previous state. In this case, a default + 'initial state' is used instead. + + The data base may be updated by 'compute state' box, but should not be update by the + 'compute page' box. The 'compute page' box should be allowed only to read the data + base. + + In this file, all the above stuff is defined, except the 'compute state' and 'compute + page' boxes. You just have to provide the function for computing a new state (compute + state) and the function for computing the page (compute page) from the new state. You + don't have to worry about state names, saving and retrieving states and the like. + + + + + + ** (1.3) What web pages are made of. + + What the client can see in his browser's window may be called a 'page'. Within a page, + we have several sorts of components: + + - 'local' components, i.e. all components which do not open a connection, like + texts, images, etc... possibly using JavaScript programmation, + + - 'actioners', which, when clicked upon, open a connection with our web site; they + may appear as links or buttons, etc... + + - 'foreign links', which when clicked upon, open a connection with another web site + (or ours eventually). + + Of course, what an actioner does is just ask our web site to perform an action. To that + end, the actioner essentially sends the name of the action to be performed. However, it + may be necessary to provide additional informations which may be seen as 'operands' of + the action. In order to attach operands to an action, HTML provides the notion of + 'form'. Indeed, a form contains essentially a set of input fields into which the client + may put values for the required operands of the action, and a submit button, which is + the actioner itself. Notice that a single form may contain several submit buttons, + which simply means that there are several distincts actions taking the same set of + operands. + + Restrictions must be put on the use of all theses gadgets. Indeed, for example, + putting a form within another form is officially meaningless in HTML, and the client's + browser may be seriously disturbed by this. In this file, we propose an interface to + the HTML language, which forbids such meaningless things, simply by imposing a strict + typing of HTML concepts. + + Each web site may be accessible through two communication channels: + + - a non secured channel (HTTP), + - a secured channel (HTTPS). + + Nevertheless, the whole thing should be considered as a single web site. For example, + you may have a secured page, obtained through HTTPS, containing public images obtained + through HTTP. An actioner in a non secured page may open a secured connection, and + conversely. + + Summarizing, a web page is made of local elements, foreign links and actioners. + Actioners receive operands from forms, and they also choose to communicate through the + non secured or through the secured channel. + + + + +-------------------+ + | page | + | | +---------------+ + | +--------------+ | | next page | + | | form | | | (non secured) | + | | +----------+ | | HTTP | | + | | | actioner |---------------------------->| | + | | +----------+ | | +---------------+ + | | | | + | | +----------+ | | +---------------+ + | | | actioner |---------------------------->| next page | + | | +----------+ | | HTTPS | (secured) | + | | | | | | + | +--------------+ | | | + | | +---------------+ + | | + +-------------------+ + + + Notice that actioners need no be necessarily put into forms. In that case, they work as + ordinary links, but they still may receive operands as we shall see. + + + + + ** (1.4) Actions. + + The client opens a new connection with our web site whenever he clicks on an + actioner. The result is that a request is sent, essentially made of a list of 'web + arguments'. Each web argument is a pair (name,value). One of these web arguments, the + 'action' web argument (whose name is "a"), determines the action to be performed. The + other web arguments (not including "s", used to identify the state) are the operands + for this action. + + Hence, the 'compute state' box in the picture above, splits naturally into as many + sub-boxes as there are actions. For this reason, we define the following type for + representing actions (where '$State' is the type representing session informations): + +public type Web_Action($State): + http_action (String name, // name of action + ($State) -> Bool allow, // true if action allowed + (HTTP_Info http_info, + List(Web_arg) web_args, // actually only 'operands' web arguments + $State state) -> $State do_it), + https_action (String name, // name of action + ($State) -> Bool allow, // true if action allowed + (HTTP_Info http_info, + List(Web_arg) web_args, // actually only 'operands' web arguments + $State state) -> $State do_it), + http_https_action (String name, + ($State) -> Bool allow, + (HTTP_Info http_info, + List(Web_arg) web_args, + $State state) -> $State do_it). + + 'http_action's are executed only under HTTP, and 'https_action's are executed only + under HTTPS. 'http_https_action's may be executed under both types of connections. + + Each action has a name, which is used to identify the action. Each action also has a + function 'allow' whose job is to verify that the action is allowed in the current + state, and a function 'do_it' for performing the action. The function 'do_it' receives + a lot of informations: + + - 'HTTP informations': + - the IP address of the client, + - the URI requested by the client (after redirection), + - the list of HTTP headers generated by the client's browser, + - the list of web arguments sent by the client (except "s" and "a"), + - the previous state (or the 'initial' or 'ticket expired' state if no previous + state can be found). + + In most cases, HTTP informations are not used. This is the reason why they are gathered + for simplicity into a unique datum of type 'HTTP_Info'. + +// For your convenience, we introduce the following simpler variants: +// +//public define Web_Action($State) +// http_action +// ( +// String name, +// $State -> Bool allow, +// (List(Web_arg),$State) -> $State do_it +// ) = +// http_action(name, +// (Maybe($State) ms) |-> if ms is +// { +// failure then true, +// success(s) then allow(s) +// }, +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is +// { +// failure then (failure, []), +// success(s2) then (success(do_it(l,s2)), []) +// }). +// +//public define Web_Action($State) +// https_action +// ( +// String name, +// $State -> Bool allow, +// (List(Web_arg),$State) -> $State do_it +// ) = +// https_action(name, +// (Maybe($State) ms) |-> if ms is +// { +// failure then true, +// success(s) then allow(s) +// }, +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is +// { +// failure then (failure, []), +// success(s2) then (success(do_it(l,s2)), []) +// }). +// +//public define Web_Action($State) +// http_https_action +// ( +// String name, +// $State -> Bool allow, +// (List(Web_arg),$State) -> $State do_it +// ) = +// http_https_action(name, +// (Maybe($State) ms) |-> if ms is +// { +// failure then true, +// success(s) then allow(s) +// }, +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is +// { +// failure then (failure, []), +// success(s2) then (success(do_it(l,s2)), []) +// }). + + + + When you define your web site, you must provide the list of all the actions of the + site. When a new state has been computed, a graphical representation of this state + must be sent to the client. To that end, you must provide a function (named below + 'compute_page') of type: + + $State -> HTTP_Answer + + where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML + pages. + +public type HTTP_Answer:... + + It should be clear that states and pages are deeply linked together. Indeed, we really + understand the page shown to the client as a representation of the current state of the + conversation between the client and the web site, but also containing informations + taken from the data bases. + + + + + + ** (1.5) States. + + Now, we explain how you can define the type (say 'State') to be used as an instance of + the type parameter '$State'. The following is just a suggestion. + + Each state determines a page (since 'compute_page' computes a page from a + state). However, some components of the state may be independant of the page. It may be + the case for example for the indication of the natural language used by the + client. Hence, a state should be made of (at least) two parts: + + - informations which are the same for all pages, + - informations which are particular to each page. + + For example, you could define: + + type Page: // one alternative per page, with particular informations + login(...), // in the components + main_page(...), + ...etc... + + Now, the type 'State' could be defined as follows: + + type State: + state(Language, // informations valid for all pages + ..., + Page). // informations particular to a page + + However, if you are making a secured web site within which clients should be identified + (by id and password), it may be a good idea to have two sorts of states, one for non + identified clients and one for identified clients. In this case, define the type + 'State' as follows (this is just a suggestion): + + type State: + non_identified(Language), + identified(String id, + Language, + Page). + + When a request arrives, check if the previous state is 'identified(...)' or + 'non_identified(...)', and don't provide access to certain pages to non identified + clients. This is required for security. + + Some more words on security. If your site needs to identify clients, define the + initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and + password of the client. If the id and password are correct, then change the state of + the client to 'identified(...)'. No other action should be able to do that. Now, be + confident that clients cannot forge states. The only information they have is the name + of a state, not the state itself which is never sent over the network, but only stored + on the server's disk. The name of the state is constructed using strong cryptographical + methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even + state names cannot be seen by a third party. So, if the system retrieves a previous + state of the form 'identified(...)', you can be confident that your client is well + identified, and you can send him confidential informations. + + States have a limited life time. It may happen that a client clicks on a button at a + time its state is out of date. In this case, this system considers that the new state + is a special state named 'ticket expired'. You must provide a function producing this + state when you describe your web site. The page corresponding to this state must just + inform the client that he/she waited a too long time before clicking on a button, and + has to restart (a new conversation) from the begining. + + + + * (2) Carrying on. + + ** (2.1) Describing your web sites. + + Before you may start your web site, you must describe it, i.e. produce a datum of the + opaque type 'Web_Site'. + +public type Web_Site:... + + Producing such a datum may be performed by: + +public define Web_Site + make_web_site_description + ( + List(String) common_names, // for example: ["www.our-business.com", + // "192.168.0.1"] + // the second one is just for testing + String site_directory, // where 'public' and other directories are + // located (should NOT end with '/') + String state_directory, + One -> One init, + (HTTP_Info, + List(Web_arg), + Bool is_https) -> $State initial_state, + ($State expired, + Maybe(String), + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_expired_state, + (Maybe(String), + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_lost_state, + List(Web_Action($State)) actions, + $State -> HTTP_Answer compute_page, + $State -> List(HTTP_header) additional_headers, + Int timeout, // seconds (todo: minutes) + Redirections redirections, + String charset, + List(String) journal_extensions, + List(String) journal_headers, + String authorization_secret, + List(MIME) known_mime_types, + (String action_name, + List(Web_arg) args)-> One before_send_file + ). + + + Explanations: + + 'common_names' is the list of names of the site (the name the browser must send as the + value of the 'Host' HTTP header in order to access the site must be in that list). Such + a name generally looks like this: + + www.somewhere.com + + If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of + the site must be exactly the same as the name on the certificate (which is precisely + called the 'common name' in the X.509 jargon). If the two names do not match, the site + will still work, but the transaction will not be transparent to the client. His browser + will complain that the name of the certificate does not match the name of the site, and + he will have to accept the certificate manually. + + 'site_directory' is the absolute path to the directory where the files needed by the + site are located. Usually this directory looks like: + + my_anubis/web_sites/www.somewhere.com + + However, this information is not computed from 'common_name', so that you can change + the common name (for example temporarily, for networking reasons) without loosing + access to the files. + + 'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state + whose graphical representation is a page explaining to the user that its 'ticket' (or + 'session information') has expired, and that he/she must close all popup windows and + start a new session. The arguments of the function contain the previous (expired) + state and all current informations concerning the user. This arguments may be useful + for example for producing the expiration message in the language chosen by the user. + You can also (and this may be much smarter) send a 'ticket prolongation page' + (including a new login for example), and resume the same conversation, since you have + all the pertinent informations at hand. In the case the ticket is definitely lost, the + second fonction 'ticket_lost_state' is used. + + Notice that despite the fact that the parameter $State is involved in the arguments of + the above function, the type 'Web_Site' does not depend on this parameter. This allows + to produce lists of web site descriptions, where each description may be constructed + with a different instance of $State. This is required because distinct sites must have + distinct types of session informations. This is made possible by the fact that the + type is obscure, and the constructor replaced by a function which assembles + 'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single + entity not depending on $State. You should have a look to the private part of this file + if you want more precisions about this programming technique. + + 'charset' is a string which will determine the character encoding to be used by the + browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252", + etc... + + 'before_send_file' is a function which is executed just before the HTTP server sends a + file. It gets an action name and the web arguments received with the request for that + file. Notice that this action name and these web arguments may be put into a + 'private_download' element, and will come back to the server at the time of the + download. + + + + ** (2.2) Directories on the server's disk. + + The description of your site contains the name of the directory within which the + required files are located. This may be for example: + + my_anubis/web_sites/www.our-business.com/ + + This is called the 'site directory' (for the given site). Within the site directory, + the following directories are created by this program: + + states + public + journal + private_download + upload_temporary + + The directory 'states' is used for storing states (session informations). Out of date + states are automatically removed after some time. + + The tree rooted at 'public' contains files that the server is allowed to send to the + clients. For security reasons, the server never sends a file which is not within the + tree whose root is this 'public' directory (except for the 'private download' mecanism; + see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis') + must have been recognized before the file may be sent. + + The directory 'journal' contains the jounal files. The roles of the remaining + directories 'private_download' and 'upload_temporary' is explained in + 'multihost_http_server.anubis', where you will also find further informations on + 'public' and 'journal'. + + + + + ** (2.3) Web servers parameters. + + The web servers have several parameters useful for administration. They are described + as follows: + + public type WebServersParameters: + wsparms(Var(Bool) shutdown_required, + + + + + ** (2.4) Starting your web sites. + + When you have described all your web sites (you may want to have several web sites, and + they are distinguished by their 'common name'), you may start them all together using + 'start_web_sites' below. This function returns a result of the following type: + +public type Start_Web_Sites_Result: + cannot_bind_to_port(Word32), + cannot_bind_to_port(Word32,Word32), + ok(Server http_server, + Server https_server). + + Indeed, it may happen that the system cannot bind (begin to listen) to one of the two + ports (or to both). The main reason is that another server is already listening on that + port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that + the 's' bit has not been set for 'user' and 'group' (there is not such problem under + Windows). Also notice that the Linux kernel may need a rather long time (up to several + minutes) before liberating a listening port. Now, if the system can bind to the two + ports, the pair of the two servers is returned. Two tools are useful for manipulating + servers: + + shutdown of type Server -> One + is_down of type Server -> Bool + + They are defined in 'predefined.anubis' (together with the type 'Server'). + + +public define Start_Web_Sites_Result + start_web_sites + ( + Word32 ip_address, // the IP address shared by the web sites + Word32 http_port, // usually: 80 + Word32 https_port, // usually: 443 + String ssl_certificate_common_name, + List(Web_Site) web_sites, // web sites to be started + (One) -> Bool shutdown_required + ). + + 'ip_address' is the IP address on which the two servers listen. If you put 0, the + servers listen on all the IP addresses of the machine. This may be useful if the + machine has several network interfaces. + + 'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec' + loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server + certificate. This is due to a problem of conception of SSL itself. See the book 'SSL + and TLS' by Eric Rescorla (at Addison Wesley) for more explanations. + + Notice that the number of servers is always 2, regardless of the number of web sites + you are starting. + + The dynamic variable 'shutdown_required' may be used to control the shutdown of the two + servers from within the web site (typically the administration part). The servers will + shutdown as soon as this variable contains 'true'. So you must provide a variable + containing 'false' otherwise your servers will not run. You may also use the primitive + 'must_restart' (see 'predefined.anubis') to control the restarting of your servers. + + + + + + + * (3) The HTML interface. + + We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination + of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more + reactive and attractive on the client side. + + + ** (3.1) Types used by the HTML interface. + + For easy reference, we gather below the definitions of all the types used by the HTML + interface, and we comment them immediately. + + +public type HTML_Size: + absolute(Int), // in pixels + percentage(Int). + + +public type Text_Option: + size(Int), // size of character font to use + font(String), // name of character font to use (such as "helvetica",...) + color(RGB), // color to be used for characters + italic, + oblique, + small_capitals, + bold, + underlined, + left_justified, + right_justified, + justified, // justified on both sides + line_through, + nowrap, + class(String), //CSS class + id(String), + style(String), + title(String), + attr(String, String). + +public define Text_Option + tooltip(String s) = title(s). + + A list of 'Text_Option' must be given with each text you want to put in your page. + + This indicate the way of reading text. +public type Reading_Way: + ltr, //the text is readable from "Left To Right" like english + rtl. //the text is readable from "Right To Left" like arabic + + +// Following types are define to prohib any arguments order error + +/** + * String value for 'id' attribut + */ +public type HtmlId: + htmlId(String id). + +/** + * String value for 'class' attribut + */ +public type HtmlClass: + htmlClass(String class). + +/** + * Name used in arguments list when form is submitted. + */ +public type WebArgName: + wan(String name). + +/** + * Value passed to arguments list when form is submitted (for RadioButton and CheckBox). + */ +public type WebArgValue: + wav(String value). + +/** + * Initial value of an input field. + */ +public type InitialValue: + init(String value). + +public define Printable_tree [HtmlId x . Printable_tree y] = str_pt(x.id, y). +public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y). +public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y). +public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y). +public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y). + + +public type HtmlEvents: + // Form element events + onchange, + onsubmit, + onreset, + onselect, + onblur, + onfocus, + // Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.) + onkeydown, + onkeypress, + onkeyup, + // Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.) + onclick, + ondblclick, + onmousedown, + onmousemove, + onmouseout, + onmouseover, + onmouseup. + +public type CoreAttrs: + id (String), + class (String), + style (String), + title (String), + lang (String), + dir (Reading_Way), + accesskey (Word8), + tabindex (Int), + attr (String, String), + event (HtmlEvents, String). + +public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false"). + +public type InputAttrs: + class (String), + style (String), + title (String), + lang (String), + dir (Reading_Way), + accesskey (Word8), + tabindex (Int), + attr (String, String), + event (HtmlEvents, String). + +public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false"). + +public define CoreAttrs + tooltip(String s) = title(s). +public define InputAttrs + tooltip(String s) = title(s). + +public type I18n: + lang (String), + dir (Reading_Way). + +//public type DIV_Option: +// id (String), +// class (String), +// style (String), +// tooltip (String), +// lang (String), +// dir (Reading_Way), +// attr (String, String), +// event (HtmlEvents, String). +// + + A list of 'DIV_Option' must be given with each DIV you want to put in your page. + +define String event_name + ( + HtmlEvents e + ) = + if e is + { + // Form element events + onchange then "onchange", + onsubmit then "onsubmit", + onreset then "onreset", + onselect then "onselect", + onblur then "onblur", + onfocus then "onfocus", + // Keyboard events + onkeydown then "onkeydown", + onkeypress then "onkeypress", + onkeyup then "onkeyup", + // Mouse events + onclick then "onclick", + ondblclick then "ondblclick", + onmousedown then "onmousedown", + onmousemove then "onmousemove", + onmouseout then "onmouseout", + onmouseover then "onmouseover", + onmouseup then "onmouseup" + }. + +public type Table_Option: + background_color(RGB), // applied to all cells in the table + background_image(String url), + border(Int width_of_outer_edge, // if not present, all values are 0 + Int width_of_top_of_relief, + Int width_of_inner_edge, + RGB border_color), + width(Int), // sets a minimal width for the table + percentage_width(Int), + attr(String name, String value), + class(String class_name). + + +public define Table_Option nude = border(0,0,0,rgb(0,0,0)). + + + A list of 'Table_Option' must be given with each table. + + +public type BackgroundOption: + repeat, // repeat the background in both directions + repeat_horizontal, // repeat the background only horizontally + repeat_vertical, // repeat the background only verticall + no_repeat, // don't repeat the background + center. + + +public type Cell_Option: + core_attrs(List(CoreAttrs)), + left, // put the content of the cell on the left + h_center, // center the content of the cell horizontally + right, // put the content of the cell on the right + top, // put the content of the cell upwards + v_center, // center the content of tye cell vertically, + bottom, // put the content of the cell downwards + base_line, // align the content vertically according to base lines + background_color(RGB), + background_image(String url, BackgroundOption), + width(Int), // sets a minimal width for the cell + percentage_width(Int), + height(Int), // sets a minimal height for the cell + columns(Int), // lets the cell span over several columns + rows(Int), // lets the cell span over several rows + nowrap, // do not allow text wrapping within the cell + class(String class_name). + + A list of 'Cell_Option' must be given with each cell and each row in a table. Options + given with a row apply to all the cells in the row, but are superseded by options given + with cells, which apply only to the cell they are given with. + + +public type HTML_Cell($T): + cell(List(Cell_Option) options, $T content). + +public type HTML_Header_Cell($T): + header_cell(List(Cell_Option) options, $T content). + + The parameter $T is later instantiated either to 'HTML_In_Form' or to 'HTML_Off_Form', + depending on where you put your table (within a form or not within a form). For your + convenience, we define the following particular case: + +public define HTML_Cell($T) + cell + ( + $T content + ) = + cell([],content). + +public define HTML_Header_Cell($T) + header_cell + ( + $T content + ) = + header_cell([],content). + + +public type HTML_Row($T): + row(List(Cell_Option) options, List(HTML_Cell($T)) cells). + +public type HTML_Header_Row($T): + empty, + header_row(List(Cell_Option) options, List(HTML_Header_Cell($T)) cells). + +public type HTML_Footer_Row($T): + empty, + footer_row(List(Cell_Option) options, List(HTML_Cell($T)) cells). + + Same remark as for 'HTML_Cell($T)'. We define several convenience functions: + +public define HTML_Row($T) + row + ( + List(HTML_Cell($T)) cells + ) = + row([],cells). + +public define HTML_Row($T) + row + ( + HTML_Cell($T) cell + ) = + row([],[cell]). + +public define HTML_Header_Row($T) + header_row + ( + List(HTML_Header_Cell($T)) cells + ) = + header_row([],cells). + +public define HTML_Header_Row($T) + header_row + ( + HTML_Header_Cell($T) cell + ) = + header_row([],[cell]). + +public type Actioner_Connection: + same, // use same type of connection as current page + http, // use non secured connection + https. // use secured connection + +public type Other_Window_Option: + resizable, // the new window may be resized by the client + scrollbars, // the new window has scrollbars + width(Int), // the new window has the specified width + height(Int). // the new window has the specified height + +public type Actioner_Target: + same, + same (String label), + other(String window_name, List(Other_Window_Option)). + +public type Actioner_Aspect: + link (List(Text_Option), String text, Maybe(String) name),// hypertext link + img_link (String img_url, String alt_text), + push_button (List(CoreAttrs),String text), + button (String url_off, String url_on), // rollover button + button (String url_off, String url_on, Int w, Int h), // idem with size + submit (List(CoreAttrs),String text), + immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices), + immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected). + + + +public type Actioner_Local_Action: + close_window. + + +public define Actioner_Aspect + link + ( + List(Text_Option) options, + String text + ) = + link(options, text, failure). + +public define Actioner_Aspect + link + ( + String text + ) = + link([], text, failure). + + +public define Actioner_Aspect + link + ( + List(Text_Option) options, + Int i + ) = + link(options,to_decimal(i), failure). + +public define Actioner_Aspect + link + ( + Int i + ) = + link([], i). + +public define Actioner_Aspect + button + ( + String url_img + ) = + button(url_img,url_img). + + Actioners are explained in details below. + + +public type TextAreaOption: + input_attrs(List(InputAttrs)), + disabled, + read_only, + wrap_lines. + +public type CSS_Style: + text_options(List(Text_Option)). + +public type CSS_File: + css_file(String file_name). + +public type JS_Attribute: + attr (String, String). + +public type JS_File: + js_file(String file_name, + List(JS_Attribute) attributes). + +public type Script: + script( String script_type, + String content). + +public define JS_File + js_file + ( + String file_name + ) = + js_file(file_name, []). + +public type HTML_Meta:... + +public type HTML_Off_Form:... + +public type HTML_Head_Tag: + meta(HTML_Meta), + title(String), + js(JS_File), + js_inline(Script), + css(CSS_File), + css_inline(String css_styles) /* Note: tags are not necessaries */ + . + + /* It contains + * - a List of HTML_Head_Tag representing necessaries head tags for the content. ex: jquery js files, js script, css specific styles, ... + * - a HTML_Off_Form representing the HTML code for the part of the page we want to display + */ +public type HTML_Partial_Content: + partial_content + ( + List(HTML_Head_Tag), + HTML_Off_Form + ) + . + +public define HTML_Partial_Content + partial_content + ( + HTML_Off_Form content + )= + partial_content([], content). + +public define List(HTML_Head_Tag) + to_HTML_Head_Tag + ( + List(CSS_File) css_file_list + )= + map((CSS_File css_f) |-> css(css_f), css_file_list). + +public define List(HTML_Head_Tag) + to_HTML_Head_Tag + ( + List(JS_File) js_file_list + )= + map((JS_File js_f) |-> js(js_f), js_file_list). + +public type HTML_In_Form: + literal_pt (Printable_tree), + literal (String), + sequence (List(HTML_In_Form) items), + text (List(Text_Option), String the_text), + preformated (List(Text_Option), String), + paragraph (List(Text_Option), HTML_In_Form content), + image (List(CoreAttrs), String url, String alternate), + image (List(CoreAttrs), String url, String alternate, Int width, Int height), + table (List(Table_Option), HTML_Header_Row(HTML_In_Form), List(HTML_Row(HTML_In_Form)), HTML_Footer_Row(HTML_In_Form)), + center (HTML_In_Form), + mail_to (String email, HTML_In_Form element), + scroller (Int width, Int height, + Int content_width, Int content_height, + HTML_In_Form content), + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect, + String action_name, List((String,String)) extra_ops, + List(Actioner_Local_Action)), + foreign_link_new (Actioner_Target, Actioner_Aspect, String url), + foreign_link (List(Text_Option), String url), + foreign_link (List(Text_Option), String url, String name), + private_download (String abs_path, String name, String extra_ext, + Maybe((String,List((String,String)))) action), + text_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width), + text_input_ro (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width), + password_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width), + text_area (List(TextAreaOption), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width, Int height), + file_upload (List(InputAttrs), String label, HtmlId id, WebArgName name, Int width), + selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices), + selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices, InitialValue selected), + // List((String,String)) = List((code,name)) where : + // code is the web-arg value + // name appears in selector + selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices), + selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected), + radio_button (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), + radio_button_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), + check_box (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), + check_box_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked), + div (List(CoreAttrs), HTML_In_Form content), + div_empty (List(CoreAttrs)), + hidden (HtmlId id, WebArgName name, InitialValue init). + + + 'HTML_In_Form' defines all the elements you may put within a form. We define a + convenience function: + +public define HTML_In_Form literal(Printable_tree t) = literal_pt(t). + +public define HTML_In_Form image(String url) = image([], url, url). + +public define HTML_In_Form image(String url, Int width, Int height) = image([], url, url, width, height). + +public define HTML_In_Form + foreign_link + ( + Int tsize, + String url, + String name + ) = + foreign_link([size(tsize)],url,name). + +public define HTML_In_Form + actioner + ( + Actioner_Connection conn, + Actioner_Target targ, + Actioner_Aspect asp, + String action_name, + List((String,String)) extra_ops + ) = + actioner(conn,targ,asp,action_name,extra_ops,[]). + +public define HTML_In_Form + actioner + ( + Actioner_Connection conn, + Actioner_Target targ, + Actioner_Aspect asp, + ) = + actioner(conn, targ, asp, "", [], []). + + +public define HTML_In_Form + text_area + ( + WebArgName name, + InitialValue init, + Int width, + Int height + ) = + text_area([], "", htmlId(""), name,init,width,height). + +public define HTML_In_Form + text_area + ( + List(TextAreaOption) options, + WebArgName name, + InitialValue init, + Int width, + Int height + ) = + text_area(options, "", htmlId(""), name,init,width,height). + +public define HTML_In_Form + table + ( + List(HTML_Row(HTML_In_Form)) rows + ) = + table([],empty,rows,empty). + +public define HTML_In_Form + table + ( + List(Table_Option) options, + List(HTML_Row(HTML_In_Form)) rows + ) = + table(options,empty,rows,empty). + +public define HTML_In_Form + table + ( + HTML_Header_Row(HTML_In_Form) h_row, + List(HTML_Row(HTML_In_Form)) rows + ) = + table([],h_row,rows,empty). + +public define HTML_In_Form + table + ( + List(Table_Option) options, + HTML_Header_Row(HTML_In_Form) h_row, + List(HTML_Row(HTML_In_Form)) rows + ) = + table(options,h_row,rows,empty). + +public define HTML_In_Form + private_download + ( + String abs_path, + String name, + String extra_ext + ) = + private_download(abs_path,name,extra_ext,failure). + +public define HTML_In_Form + private_download + ( + String abs_path, + String name, + String extra_ext, + String action_name, + List((String,String)) args + ) = + private_download(abs_path,name,extra_ext,success((action_name,args))). + +public define HTML_In_Form + text + ( + String s + ) = + text([],s). + +public define HTML_In_Form + radio_button (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) + = radio_button (options, label_text, htmlId(n.name), n, value, checked). + +public define HTML_In_Form + radio_button_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) + = radio_button_r (options, label_text, htmlId(n.name), n, value, checked). + +public define HTML_In_Form + check_box (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) + = check_box (options, label_text, htmlId(n.name), n, value, checked). + +public define HTML_In_Form + check_box_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked) + = check_box_r (options, label_text, htmlId(n.name), n, value, checked). + +public define HTML_In_Form + file_upload (WebArgName name, Int width) + = file_upload([], "", htmlId(""), name, width). + +public define HTML_In_Form + hidden (WebArgName name, InitialValue init) + = if name is wan(web_name) then + hidden(htmlId(web_name), name, init). + +public type HTML_Body:... + +public type HTML_Off_Form: + literal_pt (Printable_tree), + literal (String), + sequence (List(HTML_Off_Form) items), + text (List(Text_Option), String the_text), + preformated (List(Text_Option), String), + paragraph (List(Text_Option), HTML_Off_Form content), + image (List(CoreAttrs), String url, String alternate), + image (List(CoreAttrs), String url, String alternate, Int width, Int height), + table (List(Table_Option), HTML_Header_Row(HTML_Off_Form), List(HTML_Row(HTML_Off_Form)), HTML_Footer_Row(HTML_Off_Form)), + center (HTML_Off_Form), + mail_to (String email, HTML_Off_Form element), + scroller (Int width, Int height, + Int content_width, Int content_height, + HTML_Off_Form content), + fixed_size (HTML_Size width, HTML_Size height, HTML_Off_Form content), + fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file), + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect, + String action_name, List((String,String)) extra_ops, + List(Actioner_Local_Action)), + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect, + String action_name, List((String,String)) extra_ops, + List(Actioner_Local_Action), String form_name), + foreign_link_new (Actioner_Target, Actioner_Aspect, String url), + foreign_link (List(Text_Option), String url), + foreign_link (List(Text_Option), String url, String name), + private_download (String abs_path, String name, String extra_ext, + Maybe((String,List((String,String)))) action), + label (String name), + form (HtmlId form_id, List(CoreAttrs), HTML_In_Form content), + form (HtmlId form_id, List(CoreAttrs), + String action_name, List((String,String)) extra_ops, + HTML_In_Form content), + div (List(CoreAttrs), HTML_Off_Form content), + div_empty (List(CoreAttrs)), + iframe (List(CoreAttrs), + List(CSS_Style) /*styles*/, + List(CSS_File) /*css_files*/, + List(JS_File) /*js_files*/, + HTML_Body /*body*/). + + 'HTML_Off_Form' defines all the elements you may put outside any form. + + +public define HTML_Off_Form image(String url) = image([], url, url). + +public define HTML_Off_Form image(String url, Int width, Int height) = image([], url, url, width, height). + +public define HTML_Off_Form + form + ( + String form_name, + List(CoreAttrs) options, + HTML_In_Form content + ) = + form(htmlId(form_name), options, content). + +public define HTML_Off_Form + form + ( + String form_name, + List(CoreAttrs) options, + String action_name, + List((String,String)) extra_ops, + HTML_In_Form content + ) = + form(htmlId(form_name), options, action_name, extra_ops, content). + + +public define HTML_Off_Form literal(Printable_tree t) = literal_pt(t). +public define HTML_Off_Form fixed_size(HTML_Size width, HTML_Size height, String name_of_HTML_file) + = fixed_size_2(width,height,name_of_HTML_file). + + +public define HTML_Off_Form + foreign_link + ( + Int tsize, + String url, + String name + ) = + foreign_link([size(tsize)],url,name). + + +public define HTML_Off_Form + actioner + ( + Actioner_Connection conn, + Actioner_Target targ, + Actioner_Aspect asp, + String action_name, + List((String,String)) extra_ops + ) = + actioner(conn,targ,asp,action_name,extra_ops,[]). + +public define HTML_Off_Form + table + ( + List(HTML_Row(HTML_Off_Form)) rows + ) = + table([],empty,rows,empty). + +public define HTML_Off_Form + table + ( + List(Table_Option) options, + List(HTML_Row(HTML_Off_Form)) rows + ) = + table(options,empty,rows,empty). + +public define HTML_Off_Form + table + ( + HTML_Header_Row(HTML_Off_Form) h_row, + List(HTML_Row(HTML_Off_Form)) rows + ) = + table([],h_row,rows,empty). + +public define HTML_Off_Form + table + ( + List(Table_Option) options, + HTML_Header_Row(HTML_Off_Form) h_row, + List(HTML_Row(HTML_Off_Form)) rows + ) = + table(options,h_row,rows,empty). + + We add two convenience functions for 'row'. The reason why we add two functions, one + for 'HTML_In_Form' and one for 'HTML_Off_Form', is that adding a schema with an + arbitrary '$T' creates too many ambiguities. This is due to the fact that, if we do so, + the arguments of the function do not refer to any of the types defined here. + +public define HTML_Row(HTML_In_Form) + row + ( + HTML_In_Form content + ) = + row([],[cell([],content)]). + +public define HTML_Row(HTML_Off_Form) + row + ( + HTML_Off_Form content + ) = + row([],[cell([],content)]). + + +public define HTML_Off_Form + private_download + ( + String abs_path, + String name, + String extra_ext + ) = + private_download(abs_path,name,extra_ext,failure). + + +public define HTML_Off_Form + private_download + ( + String abs_path, + String name, + String extra_ext, + String action_name, + List((String,String)) args + ) = + private_download(abs_path,name,extra_ext,success((action_name,args))). + +public define HTML_Off_Form + text + ( + List(Text_Option) lto, + Int i + ) = + text(lto,to_decimal(i)). + + +public define HTML_Off_Form + text + ( + Int i + ) = + text([],i). + +public define HTML_Off_Form + text + ( + String s + ) = + text([],s). + + - Cell a gap between two other cells : + +public define HTML_Cell(HTML_Off_Form) + width_gap + ( + Int w + ) = + cell([width(w)],text([],"")). + +public define HTML_Cell(HTML_In_Form) + width_gap + ( + Int w + ) = + cell([width(w)],text([],"")). + + + - Row a gap between two other rows : + +public define HTML_Row(HTML_Off_Form) + height_gap + ( + Int h + ) = + row([],[cell([height(h)],text([],""))]). + +public define HTML_Row(HTML_In_Form) + height_gap + ( + Int h + ) = + row([],[cell([height(h)],text([],""))]). + + + Notice that the two types have alternatives in common (same name, same arguments types, + up to the value of the parameter $T), which correspond to elements which may be put + anywhere in the page. + + + + +define String + format + ( + List(Text_Option) l + ). + + + + +define Printable_tree + format_css_styles + ( + List(CSS_Style) l + ) = + if l is + { + [ ] then [ ], + [h . t] then + [ if h is + { + text_options(tos) then + [" body, span, p { ", format(tos), " }\n" ] + } + . format_css_styles(t)] + }. + + + +public type HTML_Meta: + keywords (List(String)), + refresh (Actioner_Connection connection, + Actioner_Target target, + String action_name, + Int delay), // in seconds + refresh (String url, Int delay), // in seconds + meta (String name, String content), + http_equiv (String name, String content), + generic_meta (List((String,String))), + literal (String). + + Meta tags are put in the 'head' of the HTML page. + + +public type Body_Option: + core_attrs(List(CoreAttrs)), + background_color (RGB), + background_image (String url), + background_image (String url, List(BackgroundOption)). + +public type HTML_Body: + body(List(Body_Option) options, HTML_Off_Form content). + + +public type HTTP_Answer: + html_page (HTTP_Status /*http_status*/, + List(HTML_Head_Tag) /*html tags*/, + HTML_Body /*body*/), + html_page (HTTP_Status /*http_status*/, + String /*title*/, + List(HTML_Meta) /*meta_tags*/, + List(CSS_Style) /*styles*/, + List(CSS_File) /*css_files*/, + List(JS_File) /*js_files*/, + List(Script) /*script*/, + HTML_Body /*body*/), + plain_text (HTTP_Status /*http_status*/, + String /*text*/), + custom_text (HTTP_Status /*http_status*/, + String /*mime_type*/, + String /*content*/), + custom_binary(HTTP_Status /*http_status*/, + String /*mime_type*/, + ByteArray /*content*/, + List(HTTP_header)/*other headers*/), + custom_tree (HTTP_Status /*http_status*/, + String /*mime_type*/, + Printable_tree /*content*/), + http_raw (Printable_tree), + html_content (HTTP_Status /*http_status*/, + HTML_Off_Form). + + +public define HTTP_Answer + html_page + ( + String title, + List(HTML_Meta) metas, + HTML_Body body + ) = + html_page(http_ok, title,metas,[],[],[],[],body). + +public define HTTP_Answer + html_page + ( + String title, + List(HTML_Meta) metas, + List(CSS_Style) styles, + HTML_Body body + ) = + html_page(http_ok, title, metas, styles, [], [], [], body). + + 'HTTP_Answer' represents the final product of the construction of a web page. + + + + + *** (3.2) ``in form'' versus ``off form''. + + There is a variety of HTML elements: texts, buttons, links, forms, inputs, etc... Some + of them may have a content, which is yet another HTML element (or several). Hence, it + is meaningful to say that an element is 'within' another one. Now, putting any element + within any other one may be meaningless. For example, an input element must be put + within a form (otherwise, it is useless), and a from within another form has no precise + meaning (and is forbidden by the HTML specification). + + Actually, the main criterium is ``within a form or not within a form''. So, HTML + elements in a given page are separated into two categories: those who are within a + form, and the others. Nevertheless, there are elements which may belong to both + categories, like images and texts. We want to make use of the strong typing mecanism of + Anubis in order to forbid non meaningful placement of elements. + + The type 'HTML_In_Form' defines elements to be put within forms. Similarly, + 'HTML_Off_Form' defines elements not to be put within forms. Both types are recursive, + and 'HTML_Off_Form' refers to 'HTML_In_Form' (via the 'form' alternative, of course), + but the two types are not cross recursive. This is the reason why it is impossible to + put a form within a form. In order to construct a web page, you essentially have to + produce a datum of type 'HTML_Off_Form' (maybe containing data of type 'HTML_In_Form'). + + In practice, you don't have to worry so much about these two types, because elements + which may be put anywhere are constructed for both types by functions with the same + name and the same arguments. Hence, for both types, you just write the same thing. You + are warned by the compiler only when you try to put an element at a place it is not + allowed. + + + + *** (3.3) Defining your own style. + + We provide generic tools for constructing HTML elements. However, your web site needs + to have a ``style''. + + To that end, you need to write down a set of ``styling functions'', using the tools + defined here. These styling functions allow the introduction of your colors and other + visual characteristics into the constructed elements once and for all. For example, you + may want all your texts to be rendered in the ``Helvetica'' font, in size 14 and using + some 'text_color'. You may write something like this: + + define RGB text_color = rgb(10,40,40). + + define HTML_Off_Form + text + ( + String the_text + ) = + text([font("helvetica"),size(14),color(text_color)], + the_text). + + (and the same one for type 'HTML_In_Form') so that in order to put a piece of text in a + page, you just write: + + text("... some text ...") + + and you don't have to provide the font, size and color for each text. If you want to + have several styles of text presentation, you just write several sets of such + convenience functions. This also suggests a trick. You may want for example different + colors for 'in form' texts and 'off form' texts. This may be achieved automatically by + defining two functions as above, with the same name and same argument type, but + returning either a 'HTML_In_Form' or a 'HTML_Off_Form'. + + If this preliminary work is well done, you will not waste your time later when you + concentrate on the actual informational content of your pages. + + This general principle should be applied to all sorts of elements. This is the best + thing to do in order to separate the functions defining the visual style from the + functions defining the informational content itself, so that changing the style without + changing the content becomes easy. This is also the best way for having a clean and + easily readable source for your web site. + + + + + + *** (3.4) Actioners and forms. + + We have gathered several notions from HTML into that of an 'actioner'. An actioner is + an HTML element which opens a connection to our server when clicked upon. Actioners may + have different visual aspects. They may look like hypertext links or like buttons + (rollovers), or even like selectors (with immediate action). In any case, their + behavior is the same: they open a connection to our server, and send a set of 'web + arguments', i.e. pairs 'name=value'. Among these web arguments, one of them denotes + the action to be performed, and the others should be considered as operands for this + action. Actually, the precise behavior of the actioner has several variants. + + The connection with the server may be secured (HTTPS) or non secured (HTTP). See the + type 'Actioner_Connection' above. + + You must also choose where the answer must be rendered. This may be in the same window + or in another window (or frame). If it is in another window, the name of that window + must be given. If the window does not exist, the browser will create it. Optionally, + you may give the dimensions of the new window and other characteristics. See the type + 'Actioner_Target' above. + + The actioner also has a visual aspect. See the type 'Actioner_Aspect' above. In the + case of a rollover button, you provide the URLs of two images (of the same size) + representing the button: + + url_off: to be used when the mouse is not over the button, + url_on: to be used when the mouse is over the button. + + You can also create rollover buttons without creating images. Just use the second + alternative named 'button'. The server creates the images automatically. + + The purpose of forms is just to give operands to actioners. If the actioner is placed + within a form, all the input elements which are within this form provide operands to + the actioner (except sometimes when they are not set by the client). If it is not put + within a form, the actioner gets no operand, except if the name of a form is explicitly + given, in which case the actioner gets all the inputs from that form as + operands. Furthermore, you may want to give extra operands to the actioner. This may be + useful for separating families of actioners with the same action name. Extra operands + 'name=value' must be given in the form of pairs '(name,value)'. + + Notice that the name of a form may be used by an actioner which is off the form, so as + to get the operands provided by this form. Also notice that several actioners may refer + to the same form, being either in the form, or referring to the form from the + outside. These actioners simply get the same set of operands, even if they correspond + to distinct actions. + + Input elements may be put only within a form. + + + + *** (3.5) Local popup. + + This element looks like a link or a rollover button. When this button is clicked upon, + a 'popup window' appears. Actually, this popup window is just a layer in the same HTML + page, which becomes suddenly visible. It is realized with a '
' HTML tag. In + particular, clicking on the button does not open any connection. This is why it is + called 'local'. The arguments have the following roles: + + Actioner_Aspect aspect of the button (same semantics as for actioners) + content content of the popup window + x, y, position of the popup window on the HTML page (not relative + to the button but to the page itself) + title title of the popup window + color color of the title bar and close button in the popup window. + A lightened version of this color is used for the background + of the popup window. + width width of the title bar + + + + + + --- That's all for the public part ! -------------------------------------------------- + + + + + + ----------------------------------- Table of Contents --------------------------------- + + *** [1] States. + *** [1.1] Saving and retrieving states. + *** [1.2] Deleting out of date states. + + *** [2] Tools. + *** [2.1] Directories. + *** [2.2] Secondary documents. + + *** [3] Managing web arguments. + *** [3.1] Prefixing web arguments names. + *** [3.2] Separating web arguments. + *** [3.3] Applying an action. + + *** [4] Web site descriptions and the 'awp handlers'. + *** [4.1] The type 'Web_Site'. + *** [4.2] Making a web site description. + *** [4.3] Starting the servers. + + *** [5] HTML Formating. + *** [5.1] The type 'HTML_Any($T)'. + *** [5.2] Formating a color. + *** [5.3] Creating buttons. + *** [5.4] Formating an actioner. + *** [5.5] Formating a private download link. + *** [5.6] Formating rows and cells in a table. + *** [5.7] Formating elements which may be put anywhere. + *** [5.8] Formating 'in form' elements. + *** [5.9] Formating 'off form' elements. + *** [5.10] Formating meta-tags. + + --------------------------------------------------------------------------------------- + + + + +public define String + doctype_w3c_header + = + "\n". + +public define String + html_header + = + "\n". + + + *** [1] States. + + We have to define functions for saving a state, retrieving a state, deleting out of + date states. We need one such function per web site. The types of the first two + functions depend on the parameter $State. This is not the case of the third one. The + fact that the instance of $State is variable from one web sites to the other implies + rather subtle manipulations using full functionality. + + + *** [1.1] Saving and retrieving states. + + Each state is saved into a file on the server's disk (in the directory represented by + the symbol 'state_directory', which is 'my_anubis/web_sites/common_name/states'). The + state is saved together with a time stamp whose value is obtained by adding the current + time to the given timeout for states. The state receives a name obtained by hashing + (using sha1) the content of the file itself, and then encoding the hash with + 'web_arg_encode'. The name of the file into which the state is saved is the + concatenation of "s" and the name of the state. + +read CXM_web_arg_encode.anubis + + The tool below constructs the function which is able to save a state on the server's + disk. + +define ($State s) -> String // the function constructed returns the name of the state + make_save_state_function + ( + Int timeout, + String state_directory + ) = + ($State s) |-> + with time_stamp = now+timeout, + to_be_saved = (time_stamp,s), + state_name = web_arg_encode(sha1(s)), + if save(to_be_saved,state_directory+"/s"+state_name) is ok + then state_name + else (print("Cannot create state file in '"+state_directory+"'.\n"); ""). + + + When a request arrives, we need to retrieve the previous state from the server's + disk. We receive the name of that state. If the state is out of date, the state file is + kept 3 days, and then deleted. + +type PreviousState($State): + not_found, // cannot retrieve the previous state + out_of_date($State), // the previous state is out of date + still_valid($State). // the previous state is still valid + +define (String state_name) -> PreviousState($State) + make_retrieve_state_function + ( + String state_directory + ) = + (String state_name) |-> + with file_path = state_directory+"/s"+state_name, + if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d) + then ( + if d is (time_stamp,s) then + 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. + + + + *** [1.2] Deleting out of date states. + + We also need to delete states which are out of date and which will never be deleted by + the above method. This may be performed by a machine doing this periodically (say once + per states life time period). + +define (List(String) file_names) -> One + make_delete_out_of_date_states_function + ( + Maybe($State) dummy, + String state_directory + ) = + (List(String) file_names) |-df-> + if file_names is + { + [ ] then unique, + [h . t] then + with file_path = state_directory+"/"+h, + if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d) + then ( + if d is (time_stamp,data) then + if time_stamp < now + then (forget(remove(file_path)); df(t)) + else df(t) + ) + else (forget(remove(file_path)); df(t)) + }. + + + The 'labelled arrow' |-df-> is documented in 'documentation/en/anubis_doc.txt'. + + Note: The argument 'dummy' (of type Maybe($State)) is not used in the body of the + function (hence its name). Nevertheless, it is required. Indeed, the Anubis compiler + does not accept a parameter in the body of a function (here the parameter is required + by the use of 'retrieve') if this parameter does not appear in the type of the + function. This is because this would create ambiguities that no explicit typing may + ever resolve. If you put a double slash in front of the declaration of 'dummy' above, + and if you compile this file, you will get a message like this one: + + Error in 'making_a_web_site.anubis', line 1300, column 7: + A definition may not contain parameters which are not present + in the declaration part (hidden parameters): + $State + + The type of the function constructed by 'make_delete_out_of_date_states_function' is + independant of the parameter $State. This is important because this allows to create + the list of such functions for all web sites. From this list, it is possible to call + the functions one after the other, so deleting out of date states for all web + sites. Actually, the next function receives a list of pairs (state_directory,function), + one for each web site. + +define One + delete_out_of_date_states // for all web sites + ( + List((String, List(String) -> One)) directories_and_functions + ) = + if directories_and_functions is + { + [ ] then unique, + [h . t] then if h is (state_directory,function) then + function(directory_list(state_directory,"s*")); + delete_out_of_date_states(t) + }. + + + The above function must be called periodically in a separate virtual machine. The + period we have choosen is (rather logically) the life time of states itself. This may + be achieved by an 'infinite' loop, using a 'sleep(timeout)'. However, the loop must not + be really infinite, because the servers may be shutdown. Hence, our loop must test + (rather frequently; say every second) if the servers are down. If they are, the loop + must be exited. + +define One + delete_states_loop + ( + List((String,List(String) -> One)) directories_and_functions, + Int timeout, + Int next_time, + Server http_server, + Server https_server, + (One) -> Bool shutdown_required + ) = + if shutdown_required(unique) + then (shutdown(http_server); shutdown(https_server)) + else unique; + if (is_down(http_server) & is_down(https_server)) + then unique + else if now > next_time + then + ( + delete_out_of_date_states(directories_and_functions); + delete_states_loop(directories_and_functions, + timeout, + now+timeout, + http_server, + https_server, + shutdown_required) + ) + else + ( + sleep(1000); // sleep just one second and try again + delete_states_loop(directories_and_functions, + timeout, + next_time, + http_server, + https_server, + shutdown_required) + ). + + The above loop must be run in a separate virtual machine. This will be done just after + the two servers are started. + + + + + + *** [2] Tools. + + *** [2.1] Directories. + + We need a tool for creating directories (if needed). + + (This tool has been moved to 'tools/basis.anubis'). + + + + + *** [2.2] Secondary documents. + + Some HTML elements (like '', '') cannot receive their content directly + from the current document, but only through an URL. For this reason, we implement a + mecanism for creating secondary documents on the fly. To that end we use the 'private + download' mecanism. + + A secondary document is formated by the same functions as the main document itself. The + next function takes an 'off form' element, creates the file containing the secondary + document in HTML format, and returns the URL at which the document will be available. + +define String + create_secondary_document + ( + String sd, // site directory + String as, // authorization_secret + String sn, // state name + $T -> Printable_tree format_element, + $T content, + HTML_Size width + ) = + with private_download_directory = sd+"/private_download", + hash = web_arg_encode(sha1(content)), + file_content = (Printable_tree) + [doctype_w3c_header, + "
", + format_element(content), + "
" + ], + file_name = "sd"+hash+".html", + file_path = private_download_directory+"/"+file_name, + if write_to_file(file_path,file_content) is + { + cannot_open_file then print("Cannot open file '"+file_path+"'.\n"); "", + write_error(n) then print("Error writing file '"+file_path+"'.\n"); "", + ok then file_name+"?zauth="+ + make_authorization(sd,as,private_download_directory+"/"+file_name) + }. + + + + + *** [2.3] Generating unique ids. + + In order to uniquely name object for JavaScript we generate unique ids from a counter. + +define Int + new_idnum + ( + Var(Int) ic_v // 'idnum' counter variable + ) = + protect + with result = *ic_v+1, + ic_v <- result; + result. + + + + + + + *** [3] Managing web arguments. + + Web arguments are those pairs 'name=value' which are transmitted through the HTTP + protocol. We need precise naming conventions for these web arguments. + + + + *** [3.1] Prefixing web arguments names. + + CR 2008-07-08 Prefixing Removed + + + + *** [3.2] Separating web arguments. + + When a new request arrives, we need to separate the web arguments, that is to say: + + - find the value of "s", and recover the corresponding state, + - find the value of "a", which is the name of the action to be performed, + - get the list of all the remaining web arguments (operands of the action). + + We must also determine if the previous state may be recovered. If it is not the case + (either because the previous state name is invalid, or the previous state is out of + date), we must check if there is an action name. Indeed, the presence of an action name + indicates that the user has clicked on one of our buttons or links. If on the contrary + there is no action name the user has just entered our address in his browser. In this + last case, we must send the first page of our site (maybe a 'login' page), but if there + is an action, we must send a page just saying that the session ticket has expired. If + the previous state is recovered and there is no action, the new state is the same as + the previous state. + + The result of the separation of the web arguments is of type: + +type Separated_Web_Args($State): + swa(PreviousState($State) previous_state, + Maybe(String) action_name, + List(Web_arg) operands). + + + + The next function constructs the function which separates the web arguments. + +define (List(Web_arg) lwa, HTTP_Info info) -> Separated_Web_Args($State) + make_separate_web_args_function + ( + String state_directory, + String -> PreviousState($State) retrieve_state, + String website_name + ) = + (List(Web_arg) lwa, HTTP_Info info) |-swaf-> + if lwa is + { + [ ] then + // + // no web arg found => no previous state and no action + // + if find_cookie("state_"+website_name, server_get_cookies(http_headers(info))) is + { + failure then swa(not_found,failure,[]), + success(cookie) then swa(retrieve_state(value(cookie)),failure,[]) + }, + + //swa(failure,failure,[]), + + [wa_1 . wa_others] then + // + // at least one web arg => + // separate other web args, and insert the first one as needed + // + if (Separated_Web_Args($State))swaf(wa_others, info) is + { + swa(ps1, // possible previous state + an1, // maybe an action name + op1) // operands so far + then + if wa_1 is + { + web_arg(n, value) then + with name = if substr(n,0,4) = "amp;" then substr(n, 4, length(n) - 4) else n, + if name = "a" then + swa(ps1,success(value),op1) + else if name = "t" then + swa(ps1,an1,[web_arg("target",value) . op1]) + else + swa(ps1,an1,[web_arg(name,value) . op1]), + + upload(n,v,t) then + swa(ps1,an1,[wa_1 . op1]) + } + } + }. + + + + + + + *** [3.3] Applying an action. + + When the web arguments are separated (and their names cleaned up from prefixes), we may + apply the action to the operands and the current state. We search for the action to be + applied in the list of actions. If no action is found, the new state is the same as + the previous state. Also, we deny the application of an HTTP action if the request + arrives through the HTTPS channel and conversely. + + +define ($State previous, + String action_name, + HTTP_Info http_info, + List(Web_arg) lwa, + Bool is_https) -> $State + make_apply_action_function + ( + List(Web_Action($State)) actions_list + ) = + with f = + ($State previous, + String action_name, + HTTP_Info http_info, + List(Web_arg) lwa, + Bool is_https, + List(Web_Action($State)) actions) |-f-> + //println("Looking for action ["+action_name+"]"); + if actions is + { + [ ] then print("action '"+action_name+ + "' not found.\n"); previous, + [ac1 . others] then if ac1 is + { + http_action(an,allow,do_it) then + if an = action_name + then if is_https + then (print("HTTP action '"+an+ + "' called through HTTPS (denied).\n"); + previous) + else if allow(previous) + then do_it(http_info,lwa,previous) + else previous + else f(previous,action_name,http_info,lwa,is_https,others), + + https_action(an,allow,do_it) then + if an = action_name + then if is_https + then if allow(previous) + then do_it(http_info,lwa,previous) + else previous + else (print("HTTPS action '"+an+ + "' called through HTTP (denied).\n"); + previous) + else f(previous,action_name,http_info,lwa,is_https,others), + + http_https_action(an,allow,do_it) then + if an = action_name + then + //println("Action ["+action_name+"] found"); + if allow(previous) + then do_it(http_info,lwa,previous) + else previous + else f(previous,action_name,http_info,lwa,is_https,others), + + } + }, + ($State previous, + String action_name, + HTTP_Info http_info, + List(Web_arg) lwa, + Bool is_https) |-> + f(previous, action_name, http_info, lwa, is_https, actions_list). + + + + + + + + + *** [4] Web site descriptions and the 'awp handlers'. + + *** [4.1] The type 'Web_Site'. + + The type 'Web_Site_Description' is defined in 'web/multihost_http_server.anubis'. We + need another one, because, we have some extra informations to record for each site. + +public type Web_Site: + web_site((Word32,Word32) -> Web_Site_Description description, + List(String) -> One delete_out_of_date). + + + + + *** [4.2] Making a web site description. + + Below is the function which creates a web site description. It first creates (if + needed) the directories for the site, then constructs the tool functions for the site, + and the site handler. Finally, it constructs the web site description. + + We gather common (constant) informations in the following type: + +public type CommonInfo: + info(String common_name, + Word32 http_port, + Word32 https_port, + String site_directory, + String authorization_secret + ). + + We need a forward declaration. + +public define Printable_tree + format + ( + CommonInfo cinfo, + String state_name, + List(HTTP_header) headers, + HTTP_Answer page, + Bool is_https, + String charset + ). + + +define Printable_tree + format + ( + HTML_Size s + ) = + if s is + { + absolute(x) then ["\"",x,"\""], + percentage(x) then ["\"",x,"%\""] + }. + +define List(HTTP_header) + make_state_cookie_headers + ( + String website_name, + String state_name + ) + = + [ + http_header("Set-Cookie", "state_"+website_name+"="+state_name) + ] + . + + public define Web_Site + make_web_site_description + ( + List(String) common_names, // for example: ["www.our-business.com", + // "192.168.0.1"] + // the second one is just for testing + String site_directory, // where 'public' and other directories are + // located (should NOT end with '/') + One -> One init, + (HTTP_Info, + List(Web_arg), + Bool is_https) -> $State initial_state, + ($State expired, + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_expired_state, + (HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_lost_state, + List(Web_Action($State)) actions, + $State -> HTTP_Answer compute_page, + $State -> List(HTTP_header) additional_headers, + Int timeout, // seconds (todo: minutes) + Redirections redirections, + String charset, + List(String) journal_extensions, + List(String) journal_headers, + String authorization_secret, + List(MIME) known_mime_types, + (String action_name, + List(Web_arg) args)-> One before_send_file + ). + + +public define Web_Site + make_web_site_description + ( + String website_name, + List(String) common_names, // for example: ["www.our-business.com"] + String site_directory, + String state_directory, + One -> One init, + (HTTP_Info, + List(Web_arg), + Bool is_https) -> $State initial_state, + ($State expired, + Maybe(String), + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_expired_state, + (Maybe(String), + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_lost_state, + List(Web_Action($State)) actions, + $State -> HTTP_Answer compute_page, + $State -> List(HTTP_header) additional_headers, + Int timeout, + Redirections redirections, + String charset, + List(String) journal_extensions, + List(String) journal_headers, + String secret, + List(MIME) known_mime_types, + (String action_name, + List(Web_arg) args) -> One before_send_file + //Bool using_state_cookies + ) = + 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_state = make_save_state_function(timeout, state_directory), + retrieve_state = make_retrieve_state_function(state_directory), + separate_web_args = make_separate_web_args_function(state_directory, retrieve_state, website_name), + 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) + if separate_web_args(lwa, http_info) is + { + swa(mb_previous_state, mb_action_name, operands) then + with new_state = if mb_previous_state is + { + not_found then + //println("previous state not found"); + if mb_action_name is + { + failure then initial_state(http_info, operands, is_https), + success(_) then + ticket_lost_state(mb_action_name, http_info,operands,is_https) + }, + + out_of_date(state) then + ticket_expired_state(state, mb_action_name, http_info,operands,is_https), + + still_valid(state) then + if mb_action_name is + { + failure then state, + success(action_name) then + apply_action(state,action_name,http_info,operands,is_https) + } + }, + //if state_and_headers is (session_ticket, mb_new_state, headers) then + with state_name = save_state(new_state), + //println("Cookie new STATE NAME "+state_name); + with cookie_headers = if mb_action_name is + { + failure then [], + success(action_name) then + if substr(action_name, 0, 5)="ajax_" then + [] + else + make_state_cookie_headers(website_name, state_name) + }, + + format(info(host_name, http_port, https_port, site_directory, secret), + state_name, + additional_headers(new_state) + cookie_headers, + compute_page(new_state), + is_https, + charset) + }), + // + // make the delete_out_of_date function + // + delete_out_of_date = + make_delete_out_of_date_states_function((Maybe($State))failure, + site_directory+"/states"), + // + // 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, + secret, + known_mime_types, + site_handler(http_port,https_port), + (HTTP_Info http_info, List(Web_arg) lwa) |-> 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). + +// Compatibility function for older websites +public define Web_Site + make_web_site_description + ( + List(String) common_names, // for example: ["www.our-business.com"] + String site_directory, + String state_directory, + One -> One init, + (HTTP_Info, + List(Web_arg), + Bool is_https) -> $State initial_state, + ($State expired, + Maybe(String), + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_expired_state, + (Maybe(String), + HTTP_Info, + List(Web_arg), + Bool is_https) -> $State ticket_lost_state, + List(Web_Action($State)) actions, + $State -> HTTP_Answer compute_page, + $State -> List(HTTP_header) additional_headers, + Int timeout, + Redirections redirections, + String charset, + List(String) journal_extensions, + List(String) journal_headers, + String secret, + List(MIME) known_mime_types, + (String action_name, + List(Web_arg) args) -> One before_send_file + //Bool using_state_cookies + ) + = + make_web_site_description("", common_names, site_directory, state_directory, init, initial_state, ticket_expired_state, ticket_lost_state, actions, compute_page, additional_headers, timeout, redirections, charset, journal_extensions, journal_headers, secret, known_mime_types, before_send_file) + . + + + + *** [4.3] Starting the servers. + +public define Start_Web_Sites_Result + start_web_sites + ( + Word32 ip_address, // the IP address shared by the web sites + Word32 http_port, // usually: 80 + Word32 https_port, // usually: 443 + String ssl_certificate_common_name, + List(Web_Site) web_sites, // web sites to be started + (One) -> Bool shutdown_required + ) = + with get_description = (Web_Site ws) |-> description(ws)(http_port,https_port), + with http_server_r = + start_http_server(ip_address,http_port, + map(get_description,web_sites), + load_denial_of_service_info), + with https_server_r = + start_https_server(ip_address,https_port, + ssl_certificate_common_name, + map(get_description,web_sites), + load_denial_of_service_info), + if http_server_r is ok(http_server) + then + ( + if https_server_r is ok(https_server) + then + ( + start_http_servers_tasks(map(get_description,web_sites), + [http_server,https_server], + 600); // period of 10 minutes + delegate + delete_states_loop( + map((Web_Site ws) |-> + (site_directory(description(ws)(http_port,https_port))+ + "/states",delete_out_of_date(ws)), + web_sites), + 3600*24*3, // keep out of date states 3 days + now, + http_server, + https_server, + shutdown_required), + ok(http_server,https_server) + ) + else cannot_bind_to_port(https_port) + ) + else + ( + if https_server_r is ok(https_server) + then cannot_bind_to_port(http_port) + else cannot_bind_to_port(http_port,https_port) + ). + + +public define One + start_web_sites + ( + Word32 ip_address, // the IP address shared by the web sites + Word32 http_port, // usually: 80 + Word32 https_port, // usually: 443 + String ssl_certificate_common_name, + List(Web_Site) web_sites, // web sites to be started + (One) -> Bool shutdown_required, + Logger log + ) = + if (Start_Web_Sites_Result)start_web_sites(ip_address, + http_port, + https_port, + ssl_certificate_common_name, + web_sites, + shutdown_required) is + { + cannot_bind_to_port(n) then logError(log, "Cannot bind to port: "+n), + cannot_bind_to_port(n,m) then logError(log, "Cannot bind to ports: "+n+", "+m), + ok(s1,s2) then logInfo(log, "Servers started on ports "+http_port+" (HTTP) and "+https_port+" (HTTPS).") + }. + + + + + + *** [5] HTML Formating. + + We need to translate HTML elements as defined above into actual HTML text. + + Actioners require special informations, which must be transmitted when needed by the + 'format' functions: + + - the 'common name', which is used for URLs, + - the HTTP/HTTPS port number, + - the 'state name', which must be transmitted when the actioner is clicked upon, + - the 'form name' (if any) to which the actioner refers. + + If the actioner is off form, and if it refers to a form, the name of that form is + already known by the actioner. On the contrary, if the actioner is 'in form', it refers + implicitly to the form containing it. The name of that form is transmitted to the + 'format' functions called from within the formating of that form. + + + + + *** [5.1] The type 'HTML_Any($T)'. + + The type 'HTML_Any($T)' gathers elements which may be put anywhere in the page. The + parameter $T becomes either 'HTML_Off_Form' or 'HTML_In_Form'. + +type HTML_Any($T): + any_text (List(Text_Option), String the_text), + any_preformated (List(Text_Option), String), + any_paragraph (List(Text_Option), $T content), + any_image (List(CoreAttrs), String url, String alternate), + any_image (List(CoreAttrs), String url, String alternate, Int width, Int height), + any_table (List(Table_Option), HTML_Header_Row($T), List(HTML_Row($T)), HTML_Footer_Row($T)), + any_center ($T), + any_mail_to (String email, $T element), + any_scroller (Int width, Int height, + Int content_width, Int content_height, + $T content), + any_fixed_size (HTML_Size width, HTML_Size height, $T content), + any_fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file), + any_actioner (Actioner_Connection, + Actioner_Target, + Actioner_Aspect, + String action_name, + List((String,String)) extra_ops, + List(Actioner_Local_Action), + Maybe(String) form_name), + any_foreign_link_new (Actioner_Target, Actioner_Aspect, String url), + any_foreign_link (List(Text_Option), String url), + any_foreign_link (List(Text_Option), String url, String name), + any_private_download (String abs_path, String name, String extra_ext, + Maybe((String,List((String,String))))), + any_div (List(CoreAttrs), $T element), + any_div_empty (List(CoreAttrs)), + any_coreattrs (List(CoreAttrs)). + + + + *** [5.2] Formating a color. + + RGB colors are formatted as '#rrggbb' where rr, gg and bb are two characters + hexadecimal values. + +define String + html_format + ( + RGB color + ) = + if color is rgb(r,g,b) then + "#" + to_hexa(r) + + to_hexa(g) + + to_hexa(b). + + + The following is a very arbitrary definition of the opposite color. The thing which is + important is that it is far from the original, so that characters in 'opposite' color + are clearly visible over the original. + +define RGB + opposite + ( + RGB color + ) = + if color is rgb(r,g,b) then + rgb(255-r, + 255-g, + 255-b). + + + + + *** [5.3] Creating buttons. + + We want to be able to create buttons in the form of a pair of images (rollovers) + automatically. We use the JPEG interface, because for the time being Anubis cannot + handle other kinds of images. + + + Computing printed text length. + + define Int + printed_text_width + ( + Word8 -> Int char_size, + List(Word8) l + ) = + if l is + { + [] then (Int) 0, + [h . t] then char_size(h) + 1+ printed_text_width(char_size,t) + }. + + define Int + printed_text_width + ( + SystemFont font, + String s + ) = + printed_text_width((Word8 c) |-> word8_to_int32(width(get_char_info(font,c))), + explode(s)). + + + + Converting RGB to RGBA. + +define RGBA + to_rgba + ( + RGB color + ) = + if color is rgb(r,g,b) then rgba(r,g,b,255). + + + Drawing a 'relief'. + + define One + draw_relief + ( + RGBAImage dest, + RGBA color, + Int contrast, + Int x, + Int y, + Int width, + Int height + ) = + with l = lighten(color,contrast), + d = darken(color,contrast), + draw_rectangle(dest,rect(x,y,x+width,y+1),l); + draw_rectangle(dest,rect(x,y+1,x+1,y+height),l); + draw_rectangle(dest,rect(x+width-1,y+1,x+width,y+height),d); + draw_rectangle(dest,rect(x+1,y+height-1,x+width-1,y+height),d). + + + Creating a button background. + + define RGBAImage + create_button_background + ( + RGBA color, + Int width, + Int height + ) = + with result = create_rgba_image(width,height,color), + draw_relief(result,color,100,0,0,width,height); + draw_relief(result,color,70,1,1,width-2,height-2); + draw_relief(result,color,55,2,2,width-4,height-4); + draw_relief(result,color,35,3,3,width-6,height-6); + draw_relief(result,color,20,4,4,width-8,height-8); + draw_relief(result,color,10,5,5,width-10,height-10); + draw_relief(result,color,5,6,6,width-12,height-12); + result. + + + Drawing the text over the background. + + define One + draw_button_text + ( + RGBAImage image, + String text, + Int text_index, + Int pixel_x, + Int y, + Rectangle clip, + RGBA color, + SystemFont font, + ) = + if nth(text_index,text) is + { + failure then unique, + success(c) then + with cw = draw_system_character(image,clip,pixel_x,y,font,word8_to_int32(c),color), + draw_button_text(image,text,text_index+1,pixel_x+cw+1,y,clip,color,font) + }. + + define One + draw_button_text + ( + RGBAImage image, + String text, + Int text_width, + RGBA light_color, + RGBA dark_color, + SystemFont font + ) = + with image_width = width(image), + image_height = height(image), + x_pos = (image_width-text_width)>>1, + clip = rect(0,0,image_width,image_height), + new_light_color = lighten(light_color,150), + new_dark_color = darken(dark_color,40), + draw_button_text(image, text, 0, x_pos+2, 16, clip, new_dark_color, font); + draw_button_text(image, text, 0, x_pos, 14, clip, new_light_color, font). + + + The next function creates the two images for a button. The information given is the + main color of the button, the text of the button and the minimal width (in pixels) of + the button. The function does not create the button if the images already exist. The + two images are stored in the directory 'site_directory/buttons'. The names of the files + are of the form: + + bxxxx_off.jpg + bxxxx_on.jpg + + where the prefix 'b' is to avoid leading '-' which may perturb UNIX commands (like + 'rm'), and where 'xxxx' is created from the given informations by the formula: + + xxxx = web_arg_encode(sha1((color,text,width))) + + Hence, distinct informations give distinct file names. + + + define String // returns xxxx + create_button_images + ( + String site_directory, + RGBA color, + String text, + Int width, + SystemFont font + ) = + with xxxx = web_arg_encode(sha1((color,text,width))), + buttons_dir = site_directory+"/public/buttons", + off_filepath = buttons_dir+"/b"+xxxx+"_off.jpg", + on_filepath = buttons_dir+"/b"+xxxx+"_on.jpg", + if file_exists(on_filepath) + then xxxx + else with + text_width = printed_text_width(font,text), + button_width = max(width,text_width+12), + button_height = (Int)20, + light_color = lighten(color,60), + very_light_color = lighten(light_color,30), + dark_color = darken(color,40), + background_off = + create_button_background(color,button_width,button_height), + background_on = + create_button_background(light_color,button_width,button_height), + + draw_button_text(background_off,text,text_width,very_light_color,dark_color,font); + draw_button_text(background_on, text,text_width,very_light_color,dark_color,font); + forget(write_image_to_JPEG_file(to_JPEG(background_off), + off_filepath, + 100)); + forget(write_image_to_JPEG_file(to_JPEG(background_on), + on_filepath, + 100)); + xxxx. + + + + + + *** [5.4] Formating an actioner. + + An actioner works as follows. Assume first that it refers to a form. When it is clicked + upon, the actioner puts (via 'onMouseDown') the URL into the 'action' attribute of the + form, and submits the form, using the JavaScript command 'form_name.submit()'. If the + actioner does not refer to a form, it fires the URL directly via 'href', because in + that case, the actioner is always an tag. + + The URL itself is composed using the connection sort (same, http or https), the common + name and port number (if needed), the state name, the action name, and the extra + operands, which are put into a query string. It may look like this: + + http://common_name:port/?s=state_name&a=action_name&oname=value... + + Each extra operand is a pair of strings: (name,value). It is formated as: + + &oname=value + + +define String + format_extra_operands + ( + List((String,String)) l + ) = + if l is + { + [ ] then "", + [h . t] then if h is (n,v) then + "&"+n+"="+v+format_extra_operands(t) + }. + + + It seams that the standard requires "&" instead of "&" ! + + In case the target is another window, we need to format the options for this window. + +define String + format + ( + List(Other_Window_Option) l + ) = + if l is + { + [ ] then "", + [h . t] then if h is + { + resizable then "resizable", + scrollbars then "scrollbars", + width(w) then "width="+w, + height(h2) then "height="+h2 + } + if t is [ ] then "" else (","+format(t)) + }. + + + + Formating choices for a "] + else + [s,""] + } + ], + button(url_off,url_on) then + [ if action is + { + url(u) then ["", + "\"",url_off,"\"", + "" + ], + + button(url_off,url_on,w,h) then + [ if action is + { + url(u) then ["", + "\"",url_off,"\"", + "" + ], + + submit(options, text) then + [ + if action is + { + url(u) then ["", + text, "" + ], + javascript(s,h) then + if action_name = "" then // special case where URL (so the action_name) is provided by the form itself + // so javascript isn't needed. This is the standard HMTL way. + [""] + else + [s,""] + } + ], + + immediate_selector(options,name,size,choices) then + [ if action is + { + url(u) then ["" + ], + immediate_selector(options,name,size,choices,selected) then + [ if action is + { + url(u) then ["" + ], + }. + + + + + + + *** [5.5] Formating a private download link. + + We get the absolute path of the file to be downloaded, and the name under which it + should appear to the client. The function 'format_private_download' creates an + hypertext link for downloading the file. The secured mecanism of private download is + used. This function is called by the function which formats HTML_Any($T) elements. + + +define Printable_tree + format_private_download + ( + CommonInfo cinfo, + String sn, // state name + String abs_path, // absolute file path on server + String name, // name of file as it appears in the browser + String extra, // extra extension + Maybe((String,List((String,String)))) action + + ) = + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then + with private_download_directory = site_directory+"/private_download", + with auth = make_authorization(site_directory,secret,abs_path), + [ + "", + name, + "" + ]. + + + + + *** [5.6] Formating rows and cells in a table. + +define Int + percent + ( + Int p + ) = + if p < 0 then 0 else if p > 100 then 100 else p. + + + + + Formating cell options. + + + +define String + format + ( + BackgroundOption o + ) = + if o is + { + repeat then "", + repeat_horizontal then "; background-repeat: repeat-x", + repeat_vertical then "; background-repeat: repeat-y", + no_repeat then "; background-repeat: no-repeat", + center then "; background-position: center top" + }. + +define String + format + ( + List(BackgroundOption) l + ) = + if l is + { + [ ] then "", + [h . t] then format(h)+format(t) + }. + + +define String + format + ( + List(Cell_Option) options + ) = + if options is + { + [ ] then "", + [h . t] then + if h is + { + core_attrs(core_attr_list) then format_attrs(core_attr_list), + left then " align=\"left\"", + h_center then " align=\"center\"", + right then " align=\"right\"", + top then " valign=\"top\"", + v_center then " valign=\"middle\"", + bottom then " valign=\"bottom\"", + base_line then " valign=\"baseline\"", + background_color(c) then " bgcolor=\""+html_format(c)+"\"", + background_image(n,o) then " style=\"background: url("+n+")"+format(o)+"\"", + width(w) then " width=\""+w+"\"", + percentage_width(n) then " width=\""+percent(n)+"%\"", + height(h2) then " height=\""+h2+"\"", + columns(n) then " colspan=\""+n+"\"", + rows(n) then " rowspan=\""+n+"\"", + nowrap then " nowrap", + class(class_name) then " class=\""+class_name+"\"" + } + + format(t) + }. + + + Normalizing a list of cell options (horizontal position must be specified; the default + is 'left'). + + Formating cells in a row. + +define Printable_tree + format + ( + List(HTML_Cell($T)) cells, + $T -> Printable_tree format_element + ) = + if cells is + { + [ ] then [ ], + [h . t] then if h is cell(options,element) then + ["", + format_element(element), + "" + . format(t,format_element)] + }. + +define Printable_tree + format + ( + List(HTML_Header_Cell($T)) cells, + $T -> Printable_tree format_element + ) = + if cells is + { + [ ] then [ ], + [h . t] then if h is header_cell(options,element) then + ["", + format_element(element), + "" + . format(t,format_element)] + }. + + Formating the rows in a table. + +define Printable_tree + format + ( + List(HTML_Row($T)) rows, + $T -> Printable_tree format_element, + ) = + if rows is + { + [ ] then [ ], + [h . t] then if h is row(options,cells) then + ["", + format(cells,format_element), + "\n" + . format(t,format_element)] + }. + +define Printable_tree + format + ( + HTML_Header_Row($T) row, + $T -> Printable_tree format_element + ) = + if row is + { + empty then [ ], + header_row(options,cells) then + [" ", + format(cells,format_element), + " \n" + ] + }. + +define Printable_tree + format + ( + HTML_Footer_Row($T) row, + $T -> Printable_tree format_element + ) = + if row is + { + empty then [ ], + footer_row(options,cells) then + [" ", + format(cells,format_element), + " \n" + ] + }. + +define Printable_tree + format1 + ( + List(TextAreaOption) l + ) = + if l is + { + [] then [], + [h . t] then if h is + { + input_attrs(input_attr_list) then [format_attrs(input_attr_list) . format1(t)], + disabled then [" disabled=\"disabled\" " . format1(t)] + read_only then [" readonly=\"readonly\" " . format1(t)] + wrap_lines then [" wrap=\"wrap\" " . format1(t)] + } + }. + +define Printable_tree + format + ( + List(TextAreaOption) l + ) = + if member(l,wrap_lines) + then format1(l) + else [" wrap=\"off\" " . format1(l)]. + + + *** [5.7] Formating elements which may be put anywhere. + + The function below involves the parameter $T which is later instantiated as + 'HTML_In_Form' or as 'HTML_Off_Form'. Now, since there are dictinct 'format' functions + for these two types, and because formating of tables requires recursive calls of such + functions, it is necessary to provide the 'format' function to be called recursively as + an argument. Putting naively a call to 'format' will not work, because the compiler + will look for a function able to format data of type $T (which is at that time distinct + from any other type, including our two types). Such a function does not exist. Hence + the function to be called for formating elements must be passed as a functional + argument (called 'format_element' below). Actually, what we pass is a function taking + a unique argument of type $T. Other informations (like the name of the state) are + already in the function by way of full functionality. + + + Formating text options. They are formated in CSS syntax, to be used within a + 'style=...'. + +define String + format + ( + List(Text_Option) l + ) = + if l is + { + [ ] then "", + [h . t] then if h is + { + size(n) then "font-size:"+n+"pt", + font(fn) then "font-family:"+fn, + color(c) then if c is rgb(r,g,b) then + "color:rgb("+to_decimal(r)+","+to_decimal(g)+","+to_decimal(b)+")", + italic then "font-style:italic", + oblique then "font-style:oblique", + small_capitals then "font-variant:small-caps", + bold then "font-weight:bold", + underlined then "text-decoration:underline", + left_justified then "text-align:left", + right_justified then "text-align:right", + justified then "text-align:justify", + line_through then "text-decoration:line-through", + nowrap then "white-space:nowrap", + class(class_name)then " class=\"" + class_name +"\"", + id(id_name) then " id=\"" + id_name +"\"", + style(style_string) then " style=\"" + style_string + "\"", + title(s) then " title=\"" + s +"\"" + attr(n,v) then " " + n + "=\"" + v +"\"" + } + if t is [ ] then "" else ("; "+format(t)) + }. + + + + Formating table options. + +define String + format + ( + List(Table_Option) l, + Bool border_seen + ) = + if l is + { + [ ] then if border_seen then "" else " border=\"0\" cellspacing=\"0\" cellpadding=\"0\"", + [h . t] then if h is + { + background_color(c) then " bgcolor=\""+html_format(c)+"\""+format(t,border_seen), + background_image(url) then " background="+url+format(t,border_seen), + border(o,top,i,c) then " border=\""+o+"\" cellspacing=\""+top+"\" cellpadding=\""+i+"\""+ + //" bordercolor="+format(c)+ + format(t,true), + width(w) then " width=\""+w+"\""+format(t,border_seen), + percentage_width(p) then " width=\""+percent(p)+"%\""+format(t,border_seen), + attr(name, value) then " " + name + "=\"" + value + "\"" +format(t,border_seen), + class(name) then " class=\""+name+"\"" + } + }. + + + + + +define Printable_tree + format_scroller + ( + String sn, + Int width, + Int height, + Int content_width, + Int content_height, + Int idnum, // identifying the scroller + $T content, + $T -> Printable_tree format_element + ) = + [ + "\n", + "", + "", + "", + "", + "", + "", + (if content_width > width then + [ + "", + "", + "", + ] else [ ]), + "", + "
", + "
", + "
", + format_element(content), + "
", + "
", + "
", + "", + "", + "", + "", + "", + "
\"sroll
\"scroll
", + "
", + "", + "", + "", + "", + "", + "", + "", + "
\"scroll\"scroll
", + "
" + ]. + + + +define Printable_tree + format + ( + Body_Option o + ) = + if o is + { + core_attrs(core_attr_list) then [" " + format_attrs(core_attr_list)], + background_color(c) then [" bgcolor=\"" , (String)html_format(c), "\""], + background_image(n) then [" background=", n], + background_image(n,o2) then [" style=\"background: url(",n,")",format(o2),"\""] + + }. + + + +define Printable_tree + format + ( + List(Body_Option) l + ) = + if l is + { + [ ] then [ ], + [h . t] then [format(h) . format(t)] + }. + +define Printable_tree + add_css_files + ( + List(CSS_File) l + ) = + if l is + { + [ ] then [ ], + [h . t] then + [ ["\n" ] + . add_css_files(t)] + }. + +define Printable_tree + add_js_files_attributes + ( + List(JS_Attribute) l + ) = + if l is + { + [ ] then [ ], + [h . t] then + if h is attr(name, value) then + [ " " + name + "=\"" + value + "\"" + . add_js_files_attributes(t)] + }. + + +define Printable_tree + add_js_files + ( + List(JS_File) l + ) = + if l is + { + [ ] then [ ], + [h . t] then + [ ["\n" + . add_js_files(t)] ] + }. + +define Printable_tree + add_script + ( + List(Script) l + ) = + if l is + { + [ ] then [ ], + [h . t] then [ "\n" . add_script(t) ] + }. + +define Printable_tree + add_css_styles + ( + List(CSS_Style) css_styles + ) = + + if css_styles is + { + [] then [], + [_ . _] then [ "\n" + ] + }. + + + // The function below formats a datum of type 'HTML_Any($T)'. + +define Printable_tree + format + ( + CommonInfo cinfo, + String sn, // state_name + Var(Int) ic_v, + HTML_Any($T) element, + $T -> Printable_tree format_element, // able to format a datum of type $T + Bool is_https, + ) = + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then + if element is + { + any_text(opts , t) then + if opts is + { + [] then [t], + [_ . _] then ["",t,""] + }, + any_preformated(opts,s) then + ["
",s,"
"], + //["
",s,"
"], + any_paragraph(opts,e) then + ["",format_element(e),"

\n"], + any_image(opts, url, alt) then + ["\"",alt,"\""], + any_image(opts, url, alt, w, h) then + ["\"",alt,"\""], + any_table(opts,h_row, rows, f_row) then + ["", + format(h_row, format_element), + "",format(rows,format_element),"", + format(f_row, format_element), + "\n"], + any_center(e) then + ["
",format_element(e),"
"], + any_mail_to(email,elem) then + ["",format_element(elem),""], + any_scroller(w,h,cw,ch,c) then + format_scroller(sn,w,h,cw,ch,new_idnum(ic_v),c,format_element), + any_fixed_size(w,h,c) then + with url = create_secondary_document(site_directory,secret,sn,format_element,c,w), + ["", + "secondary document", + ""], + any_fixed_size_2(w,h,fn) then + with url = fn+"?zauth="+make_authorization(site_directory,secret, + fn), + ["", + "secondary document", + ""], + any_actioner(c,t,a,an,eo,ja,fn) then + format_actioner(cinfo,sn,c,t,a,an,eo,ja,fn,is_https), + + any_foreign_link_new(target, aspect, url) then + format_foreign_link(target, aspect, url, is_https), + + any_foreign_link(options,url) then + [""], // IE7 doesn't support the form + any_foreign_link(options,url,name) then + ["",name,""], + any_private_download(url,name,extra_ext,action) then + format_private_download(cinfo,sn,url,name,extra_ext,action), + any_div(options, e) then + [format_div_option(options), format_element(e),"\n"], + any_div_empty(options) then + [format_div_option(options), "\n"], + any_coreattrs(attributs) then + [format_attrs(attributs)] + }. + + + + + // *** [5.8] Formating 'in form' elements. + + +define Printable_tree + maybe_label + ( + String label_text, + HtmlId id + ) = + if length(label_text) > 0 then [""] + else []. + + +define Printable_tree + format + ( + CommonInfo cinfo, + String fn, // form_name + String sn, // state_name + Var(Int) ic_v, // idnum counter variable + HTML_In_Form element, + Bool is_https, + ) = + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then + with format_element = (HTML_In_Form e) |-> format(cinfo,fn,sn,ic_v,e,is_https), + if element is + { + literal_pt(t) then t, + literal(t) then [t], + sequence(l) then flat(map(format_element,l)) + text(opts,t) then + format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https), + preformated(o,s) then + format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https), + paragraph(opts,t) then + format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https), + image(opts, url, alt) then + format(cinfo,sn,ic_v,any_image(opts, url, alt),format_element,is_https), + image(opts, url, alt, w, h) then + format(cinfo,sn,ic_v,any_image(opts, url, alt, w, h),format_element,is_https), + table(opts,header_row,rows,footer_row) then + format(cinfo,sn,ic_v,any_table(opts, header_row, rows, footer_row),format_element,is_https), + center(e) then + format(cinfo,sn,ic_v,any_center(e),format_element,is_https), + mail_to(a,e) then + format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https), + scroller(w,h,cw,ch,c) then + format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https), + actioner(c,t,a,an,eo,ja) then + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https), + + foreign_link_new(target, aspect, url) then + format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https), + + foreign_link(options,url) then + format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https), + foreign_link(options,url,name) then + format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https), + private_download(url,name,extra,action) then + format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https), + text_input(options, label_text, id, name, i, w) then + [ maybe_label(label_text, id), + ""], + text_input_ro(options, label_text, id, name,i,w) then + [ maybe_label(label_text, id), + ""], + password_input(options, label_text, id, name,i,w) then + [ maybe_label(label_text, id), + ""], + text_area(opts,label_text, id, n,i,w,h) then + [ maybe_label(label_text, id), ""], + file_upload(options, label, id, n, w) then + [ maybe_label(label, id), + ""], + selector(opts, label, id, n,s,cs) then + [ maybe_label(label, id), + ""], + selector(opts, label, id, n,s,cs,sd) then + [ maybe_label(label, id), + ""], + selector_c(opts, label, id, n,s,cs) then + [ maybe_label(label, id), + ""], + selector_c(opts, label, id, n,s,cs,sd) then + [ maybe_label(label, id), + ""], + + radio_button(options, label_text, id, n, v, c) then + [ maybe_label(label_text, id), + ""], + radio_button_r(options, label_text, id, n, v, c) then + [ "", + maybe_label(label_text, id)], + check_box(options, label_text, id, n, v, c) then + [ maybe_label(label_text, id), + ""] + check_box_r(options, label_text, id, n, v, c) then + [ "", + maybe_label(label_text, id)] + div(options, e) then + format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https), + div_empty(options) then + format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https), + hidden(id, name, value) then + [""], + + }. + + + + + + + *** [5.9] Formating 'off form' elements. + + The encryption type 'multipart/form-data' is required for a form containing an upload. + + +define Bool + contains_an_upload + ( + HTML_In_Form form_content + ). + +define Bool + contains_an_upload + ( + HTML_Row(HTML_In_Form) row + ) = + mapor(contains_an_upload, + map(content,cells(row))). + +define Bool + contains_an_upload + ( + HTML_Footer_Row(HTML_In_Form) row + ) = + if row is + { + empty then false, + footer_row(_, cells) then + mapor(contains_an_upload, + map(content,cells)) + }. + +define Bool + contains_an_upload + ( + HTML_In_Form form_content + ) = + if form_content is + { + literal_pt(t) then false, + literal(t) then false, + sequence(l) then mapor(contains_an_upload,l) + text(o,t) then false, + preformated(o,s) then false, + paragraph(o,t) then false, + image(o,u,a) then false, + image(o,u,a,w,h) then false, + table(o,_,rows,f_row) then if mapor(contains_an_upload,rows) then true + else contains_an_upload(f_row), + center(e) then contains_an_upload(e), + mail_to(m,e) then false, // 'e' may but should not contain an upload + scroller(w,h,cw,ch,e) then contains_an_upload(e), + actioner(c,t,a,an,eo,ja) then false, + foreign_link_new(_,_,_) then false, + foreign_link(o,u) then false, + foreign_link(o,u,n) then false, + private_download(p,n,e,a) then false, + text_input(o,lt,l,n,i,w) then false, + text_input_ro(o,lt,l,n,i,w) then false, + password_input(o,lt,l,n,i,w) then false, + text_area(o,lt,id,n,i,w,h) then false, + file_upload(o,l,i,n,w) then true, + selector(o,l,i,n,s,c) then false, + selector(o,l,i,n,s,c,p) then false, + selector_c(o,l,i,n,s,c) then false, + selector_c(o,l,i,n,s,c,p) then false, + radio_button(o,_,_,n,v,c) then false, + radio_button_r(o,_,_,n,v,c) then false, + check_box(o,_,_,n,v,c) then false, + check_box_r(o,_,_,n,v,c) then false, + div(o,c) then contains_an_upload(c), + div_empty(o) then false, + hidden(_,_,_) then false + }. + +define String + enctype + ( + HTML_In_Form form_content + ) = + if contains_an_upload(form_content) + then " enctype=\"multipart/form-data\"" + else "". + + + +define Printable_tree + format + ( + CommonInfo cinfo, + String sn, // state_name + Var(Int) ic_v, // 'idnum' counter variable + HTML_Off_Form element, + Bool is_https, + ) = + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then + with format_element = (HTML_Off_Form e) |-> format(cinfo,sn,ic_v,e,is_https), + if element is + { + literal_pt(t) then t, + literal(t) then [t], + sequence(l) then flat(map(format_element,l)), + text(opts,t) then + format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https), + preformated(o,s) then + format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https), + paragraph(opts,t) then + format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https), + image(opts,url,alt) then + format(cinfo,sn,ic_v,any_image(opts,url,alt),format_element,is_https), + image(opts,url,alt,w,h) then + format(cinfo,sn,ic_v,any_image(opts,url,alt,w,h),format_element,is_https), + table(opts,header_row, rows, footer_row) then + format(cinfo,sn,ic_v,any_table(opts,header_row, rows, footer_row),format_element,is_https), + center(e) then + format(cinfo,sn,ic_v,any_center(e),format_element,is_https), + mail_to(a,e) then + format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https), + scroller(w,h,cw,ch,c) then + format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https), + fixed_size(w,h,c) then + format(cinfo,sn,ic_v,any_fixed_size(w,h,c),format_element,is_https), + fixed_size_2(w,h,fn) then + format(cinfo,sn,ic_v,any_fixed_size_2(w,h,fn),format_element,is_https), + actioner(c,t,a,an,eo,ja) then + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,failure),format_element,is_https), + actioner(c,t,a,an,eo,ja,fn) then + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https), + foreign_link_new(target, aspect, url) then + format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https), + foreign_link(options,url) then + format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https), + foreign_link(options,url,name) then + format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https), + private_download(url,name,extra,action) then + format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https), + label(n) then [""], + form(fn,attributs, c) then + [ + "
", + // action is set dynamically by + // the actioner using JavaScript + if fn is htmlId(id) then + format(cinfo,id,sn,ic_v,c,is_https), + "
" + ] + form(fn,attributs, action_name, extra_ops, c) then + with url = make_actioner_url(cinfo, same, same, + sn, action_name, extra_ops, is_https), + [ + "
", +// " action=\"http", +// if is_https then "s" else "", +// "://",common_name,":",http_port,"/\">", + // action is set dynamically by + // the actioner using JavaScript + if fn is htmlId(id) then + format(cinfo,id,sn,ic_v,c,is_https), + "
" + ] + div(options, e) then + format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https), + div_empty(options) then + format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https), + iframe(options, css_styles, css_files, js_files, body) then + if body is body(body_options,element) then + [ "\n", + "\n", + "\n", + add_css_styles(css_styles), + add_css_files(css_files), + add_js_files(js_files), + "\n", + "\n", // format body options + format(cinfo,sn,ic_v,element,is_https), + "\n", + "\n", + "\n", + ], + + }. + + + + + *** [5.10] Formating meta-tags. + +define Printable_tree + format_keywords + ( + List(String) l + ) = + if l is + { + [] then [ ], + [h . t] then if t is [] + then [h] + else [h , ", " . format_keywords(t)] + }. + + +define Printable_tree + format + ( + CommonInfo cinfo, + String state_name, + HTML_Meta m, + Bool is_https + ) = + if m is + { + keywords(l) then ["\n"], + refresh(co,ta,an,delay) then + ["\n"], + refresh(url,delay) then + ["\n"], + meta(n,c) then ["\n"], + http_equiv(n,c) then ["\n"], + generic_meta(l) then [" if p is (n,v) then [n,"=\"",v,"\" "], + l)), + " />\n"], + literal(s) then [s] + }. + +define Printable_tree // c'est le nôtre et c'est meilleur + format + ( + HTML_Meta m, + ) = + if m is + { + keywords(l) then ["\n"], + refresh(co,ta,an,delay) then + [" "], // TODO + refresh(url,delay) then + ["\n"], + meta(n,c) then ["\n"], + http_equiv(n,c) then ["\n"], + generic_meta(l) then [" if p is (n,v) then [n,"=\"",v,"\" "], + l)), + " />\n"], + literal(s) then [s] + }. + + +define Printable_tree + format + ( + CommonInfo cinfo, + String state_name, + List(HTML_Meta) metas, + Bool is_https, + String charset + ) = + if metas is + { + [] then [format(cinfo,state_name,http_equiv("content-type", + "text/html; charset="+charset),is_https)], + [h . t] then [format(cinfo,state_name,h,is_https) + . format(cinfo,state_name,t,is_https,charset)] + }. + +define Printable_tree + _format_html_head + ( + List(HTML_Head_Tag) lwf, + Printable_tree so_far + ) + = + if lwf is + { + [] then reverse(so_far), + [ h . t] then + if h is + { + meta(meta) then + [format(meta) . _format_html_head(t, so_far)], + title(title) then + [""+title+"\n" . _format_html_head(t, so_far)], + js(jsf) then + [add_js_files([jsf]) . _format_html_head(t, so_far)], + js_inline(jsi) then + ["\n" . _format_html_head(t, so_far)], + css(cssf) then + ["\n" . _format_html_head(t, so_far)], + css_inline(cssi) then + ["\n" . _format_html_head(t, so_far)] + } + } + . + +public define Printable_tree + format_html_head + ( + List(HTML_Head_Tag) lwf, + String charset + ) + = + with lwf = (List(HTML_Head_Tag))[ meta(http_equiv("content-type", "text/html; charset="+charset)) . lwf], + if lwf is + { + [] then + [], + [ h . t] then + _format_html_head(lwf, []) + } + . + +define Printable_tree + format + ( + CommonInfo cinfo, + String state_name, + List(HTTP_header) additional_headers, + HTTP_Answer page, + Bool is_https, + String charset + ) = + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then + with ic_v = var((Int)0), + if page is + { + html_page(status, head_tags, body) then + if body is body(options,element) then + if format(status) is (status_string, status_headers) then + with answer_body = + [doctype_w3c_header, + html_header, + + "\n", format_html_head(head_tags, charset),"\n", + + "", // format body options + format(cinfo,state_name,ic_v,element,is_https), + "\n", + + ""], + [ "HTTP/1.1 " + status_string, crlf, + format_headers(standard_headers), + format_headers(standard_headers_for("text/html", length(answer_body), success(charset))), + format_headers(status_headers), + format_headers(additional_headers), + crlf + . answer_body + ] + + html_page(status, title, metas, css_styles, css_files, js_files, script, body) then + if body is body(options,element) then + if format(status) is (status_string, status_headers) then + with answer_body = + [ doctype_w3c_header, + html_header, + "\n", + add_css_styles(css_styles), + add_css_files(css_files), + add_js_files(js_files), + add_script(script), + "\n", + "\n", + "",title,"\n", // put title + format(cinfo,state_name,metas,is_https,charset), // format the metas + "\n", + "", // format body options + //"
", + format(cinfo,state_name,ic_v,element,is_https), + //"
", + "\n", + "" + ], + [ "HTTP/1.1 " + status_string, crlf, + format_headers(standard_headers), + format_headers(standard_headers_for("text/html", length(answer_body), success(charset))), + format_headers(status_headers), + format_headers(additional_headers), + crlf + . answer_body + ], + + plain_text (HTTP_Status status, String text) then + if format(status) is (status_string, status_headers) then + [ "HTTP/1.1 " + status_string, crlf, + format_headers(standard_headers), + format_headers(standard_headers_for("text/plain", length(text), success(charset))), + format_headers(status_headers), + format_headers(additional_headers), + crlf, + text . (Printable_tree)[] + ], + + custom_text(HTTP_Status status, String mime_type, String content) then + if format(status) is (status_string, status_headers) then + [ "HTTP/1.1 " + status_string, crlf, + format_headers(standard_headers), + format_headers(standard_headers_for(mime_type, length(content), success(charset))), + format_headers(status_headers), + format_headers(additional_headers), + crlf, + content . (Printable_tree)[] + ], + custom_binary(HTTP_Status status, String mime_type, ByteArray content, List(HTTP_header) other_headers) then + if format(status) is (status_string, status_headers) then + [ "HTTP/1.1 " + status_string, crlf, + format_headers(status_headers), + format_headers(standard_headers_for(mime_type, length(content), failure)), + format_headers(status_headers), + format_headers(other_headers), + format_headers(additional_headers), + crlf, + content . (Printable_tree)[] + ], + + custom_tree(HTTP_Status status, String mime_type, Printable_tree content) then + if format(status) is (status_string, status_headers) then + [ "HTTP/1.1 " + status_string, crlf, + format_headers(standard_headers), + format_headers(standard_headers_for(mime_type, length(content), success(charset))), + format_headers(status_headers), + format_headers(additional_headers), + crlf . + content + ], + + http_raw(Printable_tree content) then content, + + html_content(HTTP_Status status, HTML_Off_Form content_HTML) then + if format(status) is (status_string, status_headers) then + with content = format(cinfo, state_name, ic_v, content_HTML, is_https), + [ "HTTP/1.1 " + status_string, crlf, + format_headers(standard_headers), + format_headers(standard_headers_for("text/html", length(content), success(charset))), + format_headers(status_headers), + format_headers(additional_headers), + crlf . + content + ], + }. + diff --git a/web/CXM_multihost_http_server.anubis b/web/CXM_multihost_http_server.anubis index 9d71bf3..8448cae 100644 --- a/web/CXM_multihost_http_server.anubis +++ b/web/CXM_multihost_http_server.anubis @@ -2108,7 +2108,7 @@ define List(HTTP_header) with headers = (List(HTTP_header)) [ http_header("Content-Type", to_String(mime_type)), - http_header("Etag", etag), + http_header("Etag", "\""+etag+"\""), http_header("Content-Length",to_decimal(size)), ], if mb_ftimes is @@ -2170,7 +2170,7 @@ define Bool if input_etag is { failure then false, - success(etag) then etag = current_etag + success(etag) then trim_token(etag, '\"') = current_etag //remove triming " because this is quoted string }. Sending the answer line, the headers and the body. @@ -2190,19 +2190,19 @@ define One One -> One action_before_send_file ) = action_before_send_file(unique); - with input_etag = http_header_value(input_headers, "If-None-Match"), + with input_etag = http_header_value(input_headers, "If-None-Match"), mb_ftimes = get_file_times(full_path), current_etag = compute_etag(full_path, mb_ftimes, size), if are_same_etag(input_etag, current_etag) is { false then forget(reliable_write(connection,to_byte_array("HTTP/1.1 200 OK"+crlf))); - forget(reliable_write(connection,[format_headers(headers + headers_for_send_file(mime_type, size, current_etag, mb_ftimes)) , crlf])); + forget(reliable_write(connection,[format_headers(headers + headers_for_send_file(mime_type, size, "\""+current_etag+"\"", mb_ftimes)) , crlf])); //forget(copy_file_to_Connection(file, connection, size)), send_file_body(desc,connection,file,size,0,filename), true then forget(reliable_write(connection,to_byte_array("HTTP/1.1 304 Not Modified"+crlf))); - forget(reliable_write(connection,[format_headers([http_header("Etag", current_etag) . headers]) , crlf])) + forget(reliable_write(connection,[format_headers([http_header("Content-length","0") . [http_header("Etag", "\""+current_etag+"\"") . headers]]) , crlf])) //send_file_body(desc,connection,file,size,0,filename) }. @@ -2250,7 +2250,12 @@ define One with path = site_directory(desc)+"/public"+uri, if (Maybe(RStream))file(path, read) is { - failure then log_journal_msg(desc,"Cannot find file '"+path+"'.\n"), + failure then + println("HTTP/1.1 404 Not Found"+path); + forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+ + "Content-Length: 0"+crlf+ + "Connection: close"+crlf+crlf))); + log_journal_msg(desc,"Cannot find file '"+path+"'.\n"), success(f) then with size = file_size(f), send_file(desc, connection, @@ -2275,7 +2280,12 @@ define One absolute_path), if (Maybe(RStream))file(absolute_path, read) is { - failure then log_journal_msg(desc,"Cannot find file '"+absolute_path+"'.\n"), + failure then + println("HTTP/1.1 404 Not Found"+absolute_path); + forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+ + "Content-Length: 0"+crlf+ + "Connection: close"+crlf+crlf))); + log_journal_msg(desc,"Cannot find file '"+absolute_path+"'.\n"), success(f) then with size = file_size(f), mime_type = if recognize_mime_type_from_uri(desc,uri) is { @@ -3121,6 +3131,21 @@ define Server -> ((RWStream) -> One) else with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)), http_https_handler(sites, connection, false, dos). + +public define One + http_direct_handler + ( + List(Web_Site_Description) sites, + RWStream conn, + DenialOfService dos + ) = + if remote_IP_address_and_port(conn) is (addr,_) then + if is_dubious_IP(addr,dos) + then print("Rejecting dubious IP address "+ip_addr_to_string(addr)+"\n") + else + with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)), + http_https_handler(sites, connection, false, dos). + define Server -> (SSL_Connection -> One) make_https_handler -- libgit2 0.21.4