pax_global_header00006660000000000000000000000064125534771530014526gustar00rootroot0000000000000052 comment=bc95b3d58aa60f6e8bc88a9e7530d94361db43c8 eliom-4.2/000077500000000000000000000000001255347715300125005ustar00rootroot00000000000000eliom-4.2/.gitignore000066400000000000000000000003351255347715300144710ustar00rootroot00000000000000*~ #* *# .#* _build eliom.install src/**/*.mllib src/**/*.mldylib src/**/*.odocl local/etc local/var/run local/var/lib local/var/log local/tmp local/var/www/distillery-* tests/distillery/distillery-* ocsigen.org-data eliom-4.2/.jenkins.sh000066400000000000000000000013131255347715300145510ustar00rootroot00000000000000opam pin add --no-action eliom . #opam pin add --no-action tyxml 'https://github.com/ocsigen/tyxml.git#master' opam pin add --no-action ocsigenserver 'https://github.com/ocsigen/ocsigenserver.git#master' #opam pin add --no-action js_of_ocaml 'https://github.com/ocsigen/js_of_ocaml.git#master' opam install --deps-only eliom opam install --verbose eliom do_build_doc () { make wikidoc cp -Rf doc/manual-wiki/*.wiki ${MANUAL_SRC_DIR} mkdir -p ${API_DIR}/server ${API_DIR}/client cp -Rf _build/src/lib/server/api.wikidocdir/*.wiki ${API_DIR}/server/ cp -Rf _build/src/lib/client/api.wikidocdir/*.wiki ${API_DIR}/client/ cp -Rf doc/index.wiki ${API_DIR}/ } do_remove () { opam remove --verbose eliom } eliom-4.2/.ocp-indent000066400000000000000000000000521255347715300145360ustar00rootroot00000000000000normal with=0 syntax=lwt mll max_indent=2 eliom-4.2/CHANGES000066400000000000000000001167721255347715300135110ustar00rootroot00000000000000===== 4.2 (2015-07-21) ===== * Add Manip.children, to get the html children of an element. * Simplify Html5 and Svg signatures using tyxml's signature functors. * Various logging improvements, in particular in Eliom_client. * Fix eliomdep's exit code when calling option "-sort". * Fix #168: call_ocaml_service always sends boolean true. * Makes server function return types covariant. * Restore compatibility with ocsigenserver 2.6 and lwt 2.4.7. * Various bugfixes and wiki updates. ===== 4.1 (2014-10-01) ===== * Compatibility with js_of_ocaml-2.5 and tyxml-3.3.0 * Improvements: ** Simplify typing of services ** Use GADT to encode service parameters (Eliom_parameter) Eliom need OCaml 4.00 at least. ** bugfixes for service parameters ** Various bugfixes and enhancement ===== 4.0 (2014-05) ===== * Main new features: ** Reactive DOM elements (thanks to a contribution by besport.com) ** PUT and DELETE services for RESTful Eliom Applications (Contribution by Domoco) ** EXPERIMENTAL: Mobile apps with Eliom. By making it possible to start the application from client-side. ** Documentation improvements * Improvements: ** Improvements in typing of services (Contribution by Jacques-Pascal Deplaix) ** Filtering data from Eliom buses ** "caml" in value or type names now replaced by "OCaml" everywhere ** New module {{{Eliom_registration.File_ct}}} to make easier to send files with their content type ** Now possible to define services in shared sections ** Adding function {{{Eliom_client.change_url}}} to change the URL without doing a request ** Adding function {{{Eliom_service.attach_coservice'}}} to attach a non-attached coservice to an URL ** Improving comet configurations: now possible to stay idle instead of being completely inactive ** Now using defaultprotocol option (from ocsigenserver) to compute URLs ** The default expiration date for cookies on client side is now 10 years ** Now possible to send files in {{{Eliom_client.call_ocaml_service}}} ** Various additions and bugfixes in {{{Manip}}}, {{{Eliom_request_info}}}, {{{Eliom_content.html5}}} (events) (contributions by besport.com) ** eliom-destillery renamed into eliom-distillery ** Templates for eliom-distillery ** New programs: eliomdoc and eliompp ** Ocamlbuild package ** Various bugfixes And many other things (see git commits) ===== 3.0.0 (2012-12-10) ===== * Language ** Generalized client values in server code ** Injections into client sections * Tools ** Added eliom-destillery for generating project scaffolds ** Support Eliom interface files (.eliomi) in eliomc, eliomdep ** eliomdep: Generate dependencies between eliom-modules ** eliomc: infer only with option -infer, drop option -noinfer ** eliomc: Basic support for -i on eliom-files ** eliom{c,dep,opt},js_of_eliom: -dump to output the intermediate code ** eliomc,js_of_eliom: always open Eliom_pervasives in eliom files * API ** Eliom_pervasives.server_function to easily access the from the client ** Get current state of a scope ** Module to access values of Eliom references in external states (Eliom_state.Ext) ** Scope names are now named scope hierarchies ** Iterate the scope hierarchy (group > session > client > request) ** Adding Eliom_parameter.(type_checker, neopt) ** Add functions to insert html5 in atom feeds ** Eliom_tools.{F,D}.html to ease creation of head-tag ** Eliom_tools.wrap_handler as an easy alernative to Eliom_registration.Customize ** Test for initial request of a client on the server * Changed server behaviour ** Eliom_state.discard_everything now also discards request state ** Don't send nodes as data when they are part of the document * Changed client behaviour ** Show progress cursor during navigation with change_page ** Improved error messages ** Fail on the client when a [server_function] or call_caml_service fails on the server * Bugfixes ** Allow % for injections directly after parentheses * Support dropped for ** Xhtml ** OCamlDuce ** Eliom_compatibility_2_1 * A myriade of bugfixes ===== 2.2.2 (2012-06-11) ===== * Fix (re-disable) generation of API doc for ocamlduce modules ===== 2.2.1 (2012-06-07) ===== Addendum to the great renaming * Eliom_cookies -> Eliom_cookie * Eliom_comet.Channels -> Eliom_comet.Channel ===== 2.2 (2012-06-02) ===== The great renaming: Make Eliom's API more coherent * Dropped Eliom_pervasives, split into ** Eliom_lib (extension of stdlib) ** Eliom_content (content creation) * Moved all Html5,Xhtml content function to Eliom_content.{Html5,Xhtml} ** {HTML5,SVG,XHTML}.M -> Eliom_content.{Html5,Svg,Xhtml}.F ** {HTML5,SVG,XHTML}.DOM -> Eliom_content.{Html5,Svg,Xhtml}.D ** Eliom_output.{Html5,Xhtml}: form functions to Eliom_content.{Html5,Xhtml} ** Eliom_client.Html5 -> Eliom_content.Html5.To_dom ** Eliom_dom -> Eliom_content.Html5.Manip ** HTML5.of_element -> Eliom_content.Html5.Of_dom.of_element * Removed default implementations in Eliom_content.{Html5,Svg,Xhtml} (was inclusion of DOM) * Rename Eliom_output to Eliom_registration * Rename Eliom_registration.Eliom_appl to Eliom_registration.App * Conform naming conventions for modules (singular, lower-case) ** XML -> Xml ** SVG -> Svg ** XML_types -> Xml_types ** XHTML_types -> Xhtml_types ** HTML5_types -> Html5_types ** Eliom_services -> Eliom_service ** Eliom_parameters -> Eliom_parameter ** Eliom_references -> Eliom_reference ** Eliom_extensions -> Eliom_extension * Approximating compatibility module for Eliom 2.1: Eliom_compatibility_2_1 ===== 2.1.1 (2012-03-20) ===== * Server: Add Eliom references of scope site * Server: Add an non-Lwt interface to volatile Eliom references * Client: Add an option to restrict usage of XHR. * Bugfixes: ** Client: More robust and portable history handling ** Client: More robust CSS preloading (change_page) ** Client: Better compatibility with Opera ===== 2.1.0 (2012-02-24) ===== * Page loading rewriten. ** We do not traverse the HTML tree anymore for retrieving links and putting events handlers, it use querySelectorAll instead. (with a fallback for older browsers) *** We do not send a sparse tree along the page anymore. *** It is faster and more resilient to ugly browser plugins ** Add css loading optimisations: It fetch the css included using @include with XHR before changing page and construct only one concatenated css. It avoids page blinking when the css change and is faster (browsers tend to render the page once per css). ** Unwrapping hand rewritten in js. ** And a lot of other optimisations. * Rework of unique nodes: ** Introduce new lightweight 'unique' node of scope request, a.k.a. DOM nodes: use it through HTML5.DOM.{div,...} or its alias HTML5.{div,...}. ** To create unique node of scope application, the function 'HTML5.M.unique ?copy' has been renamed 'HTML5.create_global_elt ?id' ** Abstract id for application node are created with "HTML.new_global_elt_id" ** Node representation now differs between the client and the server. They are unwrapped on the client to simplify the XML representation: "unique" node that have already a "Javascript DOM representation" only contains a reference to the DOM representation. * Server API Changes: ** Add Eliom_state.get_*_session_group_size to know the number of session in a session group ** Parameters of type any can't be suffixes (semantic problem) ** Add Eliom_comet.wait_timeout to notify when a client isn't active ** Allow services to setup "Cache-policy: max-age" with Text, CssText and Files modules. ** Eliom_state.discard and discard_data now accept scope request. * Client API Changes: ** add an Eliom_dom module provinding imperative function on unique HTML5.elt. (for instance {{{appendChild: ?before:'a elt -> 'b elt -> 'c elt -> unit}}}). ** HTML5.M.a_on{click,...} functions directly expect a function as parameter (XML.event_handler_of_function isn't required anymore). ** Eliom_comet: configuration option for time until timeout after the focus is lost ** Handling wrapping of int32 type. ** Onload event handlers on HTML elements are executed when they are converted to DOM (using Eliom_client.of_ functions). This allows them to be added to nodes not sent in the page. ** Calls to {{{Eliom_services.onload}}} are taken into account for services sending caml values. The handlers are executed when the call to {{{Eliom_client.caml_call_service}}} terminates. * Eliom syntax: ** Event handlers can now access the current event using the _ev variable inside {{ ... }} typed according to the attribute. ** Allow modules to be used inside client expr {{ ... }} and client_expr {{ ... }} to be used inside modules ** Add -ppopt option to eliomc * And a lot of bugfixes. ===== 2.0.2 (2001-11-30) ===== * Compatibility with js_of_ocaml-1.0.8 and tyxml-2.0.1 * API Changes: ** Eliom_output.Redirection: use 302 as default and introduce abstract nome for all the 30x HTTP code ** Eliom_output.Customize: remove unrequired Functor parameters. * Delayed URl computation: this allows relative links to be created outside of service handler. * Client: do not ignore "onload" events attached on Dom elements other than window. * Bugfixes: ** Client: do not execute change_page_uri when the middle button or any modifier key is pressed. ** Client: update correctly the location when changing page with forms. ** Server: displaying better dynlink error messages. ** Syntax extension: avoid infinite loop while parsing first-order module expression ** Eliom_parameters: fixing wrong parameter names for list of list ** Eliom_parameters: fixing bug causing stack overflow when lists parameter names were wrong ** Fixing bug with non-localized parameters and service not keeping non-attached params ** Eliom_comet: stateless channels can be registered multiple times (close #220) ===== 2.0.1 (2011-09-28) ===== * Bugfixes in eliom appl.: ** Preload css when changing page to avoid a disgraceful "flash" effect ** Use to preserve links in unique node when changing page ** Fragment in URL aren't ignored anymore ** Proper exception handling in eliomc, js_of_eliom, ... ** Display a correct URL after submitting a
===== 2.0 (2011-09-20) ===== * Bugfixes: ** Correct handling of HTTP redirections hidden by XHR ** Fix links from http to https on client application ===== 2.0-rc2 (2011-09-06) ===== * Feature: ** api history: when the api history is available, application URLs are more readable (no more {{{#!}}}) * Bugfixes: ** fix browser compatibility: it should work with Firefox (>= 3.0), Chrome (all recent version we tested), Safari 5, Opera (tested 11.51), Internet explorer (9, ie 8 almost work) ** in forms declared outside of the sp's scope, hrefs were incorrect: url calculation is now done for each request ** the function {{{Eliom_client.caml_call_service}}} was broken with some kind of services ** application cookies are now always sent ** fix incorrect sharing of type variables in the syntax extension (thanks to William Le Ferrand) ** 404 and 403 errors are not dropped by applications anymore (This fix is partial: when the page content is application content, this still does not work when an exception handler returns something else) ** Fix problems with url generation for non-attached coservices inside an application ** tail recursive marshalling and demarshalling: no more limit on the depth of data sent along the page ** Fix problems with redirection and action with `NoReload exiting the application ** Handle correctly 204 code in application (do nothing with change page, fail with caml_call_service) ** Fix escape character '>': problem with strings containing "]]>" ===== 2.0-rc1 (2011-07-15) ===== * Eliom_client.change_page type now correctly forbid to call it on non-eliom application services * Stateless implementation of comet channels * Scope and state names parameters of functions are now fused in one parameter (called scope) * Change the type of 'send' functions: forbid use of incompatible output with Eliom_output.Any together. * Change the format of page loaded by an application: all pages are sent in HTML5 format. (first answers were in HTML5 subsequent were marshalled caml tree) * XML representation is now shared by client and server: conversion to Dom nodes is made by Eliom_client.Html5.of_ functions * Remove the need for an application container: application pages are now classical HTML5 pages. * Add Eliom_pervasives.{HTML5/XML/SVG}.unique function to declare XML node handled "by reference" * Fix ocamldoc generation with Eliom_output * Eliom_appl are now stateless if no data is stored in session * Allow dynamic wrapping with values to be sent to client with caml services and comet channel * Add Eliom_react.S: server to client React signals * Add lazy site values: lazy evaluated one time per site * Option to compile without preemptive threads * And lots of simplifications and bug fixes ===== 1.91 (2011-04-08) ===== * Split the ocsigen package in three : tyxml, ocsigenserver and eliom * Rename into eliom * It's now possible to set a //priority// on services registered on the same path, to choose in which order Eliom will try them. * New implementation of internal application forms with formData when available * New build system for eliom application * No type restriction in value sent from the server to the client ===== 1.90 ===== * New module {{{Eliom_client}}} for client/server Eliom programs using js_of_ocaml. * Eliom client: calling a service from client side code. * Eliom: Services taking Caml values as parameters. * Eliom: services sending Caml values. * Eliom: new implementation of forms and links to be compatible with client side programs. * Eliom: sp parameter has been removed (now using Lwt's thread storage) * Eliom: {{{Eliom_predefmod}}} renamed {{{Eliom_output}}} * Eliom: New module {{{Eliom_output.Customize}}} to create your own register functions from another registration module * Eliom: Module {{{Eliom_sessions}}} replaced by {{{Eliom_state}}}, {{{Eliom_request_info}}} and {{{Eliom_config}}}. * Eliom: new implementation of user cookies. * Eliom: Client process cookies. Like usual browser cookies but for one client side process. * Eliom: Client process server side state data. Like session data but for one client side process. * Eliom: Client process session services. * Eliom: Session group data. Like session data but for all sessions in a session group. * Eliom: Session group services. * Eliom: session replaced by a more general concept of "server side state". States have a scope: client process, session or group of sessions. * Eliom: session tables and request cache now deprecated, replaced by //Eliom references// * Eliom client: Possible to call another service without stopping the client side program, with bookmark support and back button support. * New extension Comet to allow server -> client communication. * Eliom: client/server communication channels. * Eliom: client/server reactive programming using React. * Eliom client: syntax extension for separating client and server code. * Eliom: New module Eliom_output.Eliom_appl for registering pages that belong to the same Eliom application. * Eliom client: syntax extension and wrapping/unwrapping mechanism to access server side values in client side code. * Eliom client: Relinking the DOM on client side after loading a (portion of) page. This allows nodes created on server side to be directly used in client side code. * Eliom client: XHR redirections for Eliom applications. * Eliom: safe unmarshaling of caml values sent by client side programs * Xhtml: Xhtml5 support * Atom module and Pubsubhubbub * OpenID support * SVG module * Documentation: New tutorial * Documentation: New Eliom manual * //and many other things ...// ===== 1.3.4 ===== * Eliom: Now supporting list of lists in service parameters ===== 1.3.3 (2010-06-13) ===== * Eliom: Fix some typos in Eliom's tutorial stylesheet * Server: Fix usage of {{{accept_n}}} to avoid file descriptor leakage * XHTML: Adding missing elements and attributes in XHTML.M * Cleaning Ocsigen_cache * Eliom: Fixing actions with uploads ===== 1.3.2 (2010-04-30) ===== * Add dummy findlib packages ocsigen.xhtml*, that depend on ocsigen_xhtml*, for compatibility with previous versions. These packages might be removed in a future (major) release. * Port to Lwt 2.1.0 ===== 1.3.1 (2010-04-23) ===== * Split out ocsigen_xhtml findlib package * Configuration file: when no protocol is specified in {{{}}}, listen on IPv6 (if possible) and IPv4 (always) ===== 1.3.0 (2010-01-22) ===== * Server: Each request now has a polymorphic data table (called //request cache//), where you can store the data you want to keep during the whole page generation. * Eliom: actions now return {{{()}}}. Use the request cache to send information to fallbacks. * Eliom: CSRF-safe coservices * Eliom: the number of sessions without group by IP address is now limited * Eliom: efficient implementation of limitation of sessions by groups (or now IP) for large limits * Eliom: the number of anonymous coservices by session is now limited * Eliom: the number of anonymous coservices without session by IP address is now limited * Eliom: now possible to unregister services * Eliom: New (very) experimental module {{{Eliom_obrowser}}} to use Eliom with Obrowser * Eliom: Now possible to have constant parts in suffixes to allow URLS like {{{/param1/something/param2}}} * Eliom: services with optional suffixes * Eliom: form towards a service with suffix: it is now possible to choose whether you want the redirection towards the suffix form or not * Eliom: lists and sets in suffixes * Eliom: Now possible to create services sending custom HTTP header values or customizing the content-type * Eliom: New notion: "Non localized parameters". Can be sent to any service. * Eliom: changing the order of parameters for user type form widgets * Eliom: changing the order of parameters for user type form widgets * Eliom: Eliom_tools.menu and hierarchical_menu now compare the URL strings (was: compare the service) * Eliom: textarea now take a string (was pcdata) * Eliom: The type of the iterator for lists in parameters has changed * Eliom: New options in configuration file to set session timeouts * Server: now possible to give the config file name to reload server command * Server: now possible to do a "graceful shutdown" of the server using the "shutdown" server command * Server: now possible to add custom commands for the command pipe * Server: EXPERIMENTAL now possible to observe HTTP headers before sending the result * Xhtmlpp: the parsing now fails if a quotation for an Xhtml element contains superfluous elements. (This can cause the parsing of previously incorrect code to fail) * Staticmod/Eliom: attempting to access a file whose name contains a NULL character will result in a 403. * Server: HTTP headers containing newlines are now properly escaped. * Server: correct missing xmlns in Xhtml DTD * Server: now send last-modified and etag headers when returning a 403 * Server: Now accepting several requests at a time (as explained in "Accept()able strategies" by Tim Brecht & all) * Rewritemod: more rewriting possibilities (still very basic) * Eliom menus are now more robust when finding which item is active * Fixed handling of incorrectly-sized multipart requests. Thanks to Mauricio Fernandez for noticing the bug * Upload directory and maximum file size can now be configured on a per-site basis * Renamed the field of Ocsigen_http_frame.t * Javascript events support in Xhtml.M ; Thanks to john @ 5070.info for the patch ===== 1.2.2 (2009-10-17) ===== * Add react and lwt.unix to the list of built-in findlib packages ===== 1.2.1 (2009-09-26) ===== * Lwt 2.0 compatibility: ** Adapt to Lwt.t/Lwt.u splitting ** fix Makefile to deal with lwt.unix findlib package * Fix ocsipersist-dbm Makefile * Fix for pcre-ocaml 6.0.0 * Fix typo regarding --stubdir in configure script ===== 1.2.0 (2009-03-25) ===== * Native code version now compiled by default * Now possible to link extensions and Eliom modules statically, for example to use a native code server on platforms where native dynlink is not supported * Server: Partial requests implemented (Range HTTP header) * Build C stubs into a shared library so that bytecode executables may be not linked in custom mode; new {{{--stubdir}}} option in {{{configure}}} script * Eliom: non-attached services now called "named non-attached coservices" and created using {{{Eliom_services.new_coservice'}}} with the optional {{{name}}} parameter * Eliom: now possible to create named attached coservices using the optional {{{name}}} parameter * Eliom: now possible to write libraries for Eliom sites, loaded inside {{{}}}, but not generating any page * Eliom and server: EXPERIMENTAL now possible to make extensions that can use Eliom's data * XHTML.M's pretty printer: now possible to set the DOCTYPE manually * Eliom: now possible to set manually the DOCTYPE when registering an XHTML.M service * Redirectmod and Revproxy: now possible to do more complex rewriting * Accesscontrol: add support for {{{}}} and {{{}}} conditions * Config file: {{{aliases}}} attribute now called {{{hostfilter}}} * Revproxy and Redirectmod: now possible to filter on server, port and protocol * New extension extendconfiguration to allow dynamic changes in the configuration (mimetypes, charsets, followsymnlink, directory listing, ...) * Server: new module {{{LocalFiles}}} factoring the common parts for sending static files (with Eliom and staticmod for example), while checking that the files can safely be sent. * Now possible to use XHTML pretty printers without Ocsigen, using the {{{xhtmlpretty.cma}}} library * Add {{{Ocsigen_lib.register_exn_printer}}}, better error messages * Now possible to use the same configuration file in native code and in bytecode (.cmo/.cma filenames are internally translated to .cmxs) * Signature of Ocsigen_extensions.register_extension is now more complete and more lightweight * Userconf: the options set in the local .userconf file are kept in the enclosing {{{}}} tag * Server: possibility to ignore or to supply an alternative command-line * Ocsigen_http_client: timeout when the distant server does not exists * OCaml versions < 3.10 are not supported anymore * Extensions are now much more strict w.r.t. the syntax of configuration files * Staticmod: accessing a directory for which indexing is disallowed returns an error 404 (instead of a 403 previously) ===== 1.1.0 (2008-07-15) ===== * Lwt removed (now distributed separately) * {{{XHTML.M}}} pretty printer: fixing pretty printing of empty tags (for browser compatibility) * Eliom_duce: New pretty printer for XHTML fixing pretty printing of empty tags * Eliom: secure sessions, secure services, (absolute) https links/forms, and using secure cookies * Eliom: Adding special "void action", without any parameters * Eliom: {{{Eliom_predefmod.Redirections}}} now called {{{Eliom_predefmod.String_redirection}}}, and adding new module {{{Eliom_predefmod.Redirection}}} that use GET services without parameters as data type. * Eliom and XHTML.M: Small changes of types in interfaces * Eliom: New session ID generator * Eliom: Adding types {{{int32}}} and {{{int64}}} for parameters and forms * Eliom: Adding functions {{{lwt_get_form}}} and {{{lwt_post_form}}} for creating forms using cooperative functions * Eliom and Staticmod: now possible to give GET parameters to static pages * Eliom: Bugfix in Makefiles for native code version * Eliom forms: Adding missing types in interfaces * Eliom_tools: current page is now optional in menus * Userconf and Eliom: there was a bug when loading both Eliom and Userconf together * Reverse Proxy: Now sending content length when available * Web server: The default content-type is now {{{application/octet-stream}}} * Creating and installing a cma file for all Ocsigen libraries not installed elsewhere * Ocsipersist-dbm: fixing bug when removing data * Deflatemod: fixing memory leak * And small bugfixes in XHTML.M, Eliom, ... ===== 1.0.0 (2008-04-01) ===== * Config file: findlib integration * Eliom and Ocsigen: changing namespace convention for modules * Access control: simplification of config file syntax * Eliom: Allowing (module dependent) parameters for registration functions * New xhtml output without pretty printing * Web server: Bugfix in HTTP/1.0 with keep-alive * Reverse proxy: Bugfix GET parameters were wrong * Reverse proxy: Bugfix memory consumption when the connection was closed by client ===== 0.99.5 (2008-01-11) ===== * Revproxy: pipelining of requests * Access control: simplification, generalization of filters and syntax changes in config file * Eliom: EXPERIMENTAL session groups * Eliom: non-attached services * Eliomduce: new functor {{{SubXhtml}}} for creating registration modules * Eliomduce: new module Eliomducetools with same features as Eliomtools, but for Eliomduce * Web server: now possible to split the configuration file into several files using the {{{}}} option. * Web server: now possible to have {{{}}} option inside another {{{}}} in configuration files, and the the first one is optional * Web server: EXPERIMENTAL user configuration files, with restricted possibilities (for security reasons) * Web server: IPv6 support * Deflatemod: now possible to filter on file extensions * Eliom: new option to keep GET non-attached parameters or not when doing a POST form towards a non-attached coservice. * Eliom: bugfix path of session cookies * Eliom: bugfix POST non-attached coservices called from a page with non-attached GET parameters were not found. * Lwt: now catching exceptions raised after timeouts * Cgimod: bufixes in path handling * Web server: bugfix - some files were not closed ===== 0.99.4 (2007-11-21) ===== * Ocsigen: Changes in the extension mechanism. The extensions are not tried in the order in which they are loaded any more, but in the order in which the options are specified for each site in the configuration file. * New experimental extension: access control * A few small enhancements ** Eliom: internal cookie management rewritten (+ bugfix) ** Eliom: Small changes in function names ** Eliom: now retry all extensions after actions (not only Eliom) ** Eliom: cleaning {{{Eliommod}}} interface ** Ocsigen server: Internal changes in server (removing "send" functions, debug messages lazier) ** Lwt: Adding a few functions in {{{Lwt_chan}}} interface ** Staticmod: Allowing default error pages for HTTP errors to be customized ** Ocsipersist (dbm and sqlite): better handling of database errors ** XHTML: New pretty printer for xhtml using streams (up to 15% speedup on requests) ** XHTML: Allowing any value for {{{}}} rel attribute (for example {{{shortcut icon}}}). ===== 0.99.3 (2007-11-07) ===== * Ocsigen: New module Deflatemod to compress data before sending to the browser. * Ocsigen: EXPERIMENTAL - New module Revproxy (reverse proxy). * Eliom: New session mechanism, with the ability to name the sessions and thus have several sessions for the same site. * Eliom: Now possible to have one site with session inside a subdirectory of another one. * Lwt: New module {{{Lwt_timeout}}} to implement timeouts, new module {{{Lwt_chan}}}, new module {{{Lwt_mutex}}}, new function {{{Lwt_unix.abort}}} to make all threads waiting on a file descriptor abort with an exception. * Ocsigen: New implementation of lots of Web server internals. Better management of Ocsigen's streams, file descriptors, exceptions, timeouts ... * A lot of enhancements and bug fixes: ** Eliom: Single {{{}}} in forms, by Stéphane Dalmas * EXPERIMENTAL: The Web server is now extensible. It means that you can add modules (like Apache modules) for generating pages, filters of requests, extensions of config files. For now there are two modules, one for static pages, and one for dynamic pages. The only changes for users is that they need to dynlink staticmod.cmo and ocsigenmod.cma from the configuration file. The syntax of config file for modules and staticdir also changed. * It is now possible to specify the encoding of characters for each sub-site. * Now usable with Ocamlnet 2.2 or 1.1.2. * EXPERIMENTAL: If OCamlDuce is installed on your system, you can now use it to do the type-checking of your pages (see the documentation). Warning: This is broken with OCamlDuce 3.09.2 patch level 2. You need at least OCamlDuce 3.09.3 patch level 1. * Removing Ocsimore from the default distribution. That version of Ocsimore is not supported anymore. Ocsimore has been rewritten from scratch by Piero Furiesi. ===== 0.5.1 (2006-12-14) ===== * Bugfix Konqueror: Multipart forms with now work correctly with Konqueror * Bugfix Internet Explorer: getting around a bug of Internet Explorer while displaying page * Bugfix NetBSD: Makefile * Bugfix Debian for HPPA, Mips, Alpha: Makefile * Bugfix: preemptive.cmi was missing in the installation directory * Adding manpage (S. Mimram) * Adding logrotate configuration * Daemon mode: adding setsid and redirect stdout/stderr to /dev/null. Closing stdin. ===== 0.5.0 (2006-11-23) ===== * HTTP 1.1 improved (HEAD, ETag, keep-alive implemented, If-Modified-Since, ...) * HTTPS support * Pipelining of requests * Server can listen on several ports * Multiple servers: you can now define several servers in the config file. * Virtual hosts: filtering on hostnames/ports (with wildcards) * Asynchronous file upload with multipart support * Large file transfer improved. * MIME types are now parsed from a file * Changes in the syntax of config file * Accessors for server parameters. Use ({{{get_user_agent sp}}}) instead of {{{sp.user_agent}}}. * Page generation is now using {{{Lwt}}} cooperative threads, to make it possible the generation of several pages at the same time. Practically, add {{{Lwt.return}}} before the page you want to send, and use cooperative input/output functions. * Typing errors of parameters are now catchable. * {{{static_dir}}} is now a function * Most of global references have been removed. You now need to give sp as parameter to {{{register_for_session}}}, {{{static_dir}}}, {{{close_session}}}, etc. * Links and forms now take {{{server_params}}} instead of {{{current_url}}} ({{{sp}}} is shorter than {{{sp.current_url}}}) * EXPERIMENTAL: Use of preemptive threads for non cooperative libraries ({{{detach}}} function). * EXPERIMENTAL: The {{{Ocsigen}}} module now contains a functor {{{Make}}} to allows the use of several ways of generating XHTML. The default way (using {{{XHTML.M}}} or the syntax extension) can be used by doing {{{open Ocsigen.Xhtml}}}. There is also an untyped xhtml generation module called {{{Ocsigen.Text}}}. * EXPERIMENTAL: extension of forms. * Reorganisation of the code * Bugfixes in makefiles * Bugfix: escaping of strings in xhtml with syntax extension (thanks to David Mentre) ===== 0.4.0 (2006-06-06) ===== * Full reimplementation of the core using Generalized Algebraic Data Types, * {{{_int}}}, {{{_string}}}, etc. are now called {{{int}}}, {{{string}}}, etc. * The type {{{_http_params}}} is now called {{{server_params}}}, * Services functions now all take 3 parameters, one for server parameters, one for GET parameters, and one for POST parameters. Note that {{{**}}} is used to create **pairs** and not tuples. * The {{{a}}} and {{{post_form}}} functions now take a fix number of parameters, correponding to GET parameters. * //URLs// are now called //services//, * //state URLs// are now called //auxiliary services//, * {{{register_post_url}}} does not exist anymore. use {{{register_service}}} instead (idem for all other {{{register_post_*}}} functions). * Changes for prefix URLs * Small changes for actions * EXPERIMENTAL: sums, bool and list types for services and forms * small bugfixes ===== 0.3.27 (2006-04-27) ===== * Change the way to get server parameters ===== 0.3.26 ===== * Load unsafe modules * Other small changes ===== 0.3.25-2 (2006-02-24) ===== * Small bugfix for 64 bits processors * bugfix for static files * {{{action_link}}} is now called {{{action_a}}} ===== 0.3.24 (2006-02-07) ===== * More documentation * Change types {{{internal_url}}} and {{{external_service}}} to use polymorphic variants ===== 0.3.23 (2006-02-07) ===== * Better handling of static files and "403 Forbidden" message eliom-4.2/COPYING000066400000000000000000000654371255347715300135520ustar00rootroot00000000000000This program is released under the LGPL version 2.1 (see the text below) with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. As a special exception to the GNU Library General Public License, you may also link, statically or dynamically, a "work that uses the Library" with a publicly distributed version of the Library to produce an executable file containing portions of the Library, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Library General Public License. By "a publicly distributed version of the Library", we mean either the unmodified Library, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Library General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Library General Public License. GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! eliom-4.2/LICENSE000066400000000000000000000004131255347715300135030ustar00rootroot00000000000000The Ocsigen application core, and other portions of the official Ocsigen distribution not explicitly licensed otherwise, are licensed under the GNU LESSER GENERAL PUBLIC LICENSE with openssl linking exception -- see the 'COPYING' file in this directory for details. eliom-4.2/Makefile000066400000000000000000000041431255347715300141420ustar00rootroot00000000000000### Building BUILDER=_build/build/build.native BUILD=ocaml pkg/build.ml .PHONY: all byte opt builder all: $(BUILDER) $(BUILD) manpage=false native=true native-dynlink=true byte: $(BUILDER) $(BUILD) manpage=false native=false native-dynlink=false opt: $(BUILDER) $(BUILD) manpage=false native=true native-dynlink=true $(BUILDER): $(wildcard build/*.ml) ocamlbuild -no-plugin -I src/ocamlbuild -no-links -use-ocamlfind build/build.native 1> /dev/null builder: $(BUILDER) ### Doc .PHONY: doc wikidoc doc man alldoc DOCS_DIR=src/lib/client src/lib/server src/ocamlbuild DOCS_HTML=$(addsuffix /api.docdir/index.html,$(DOCS_DIR)) DOCS_WIKI=$(addsuffix /api.wikidocdir/index.wiki,$(DOCS_DIR)) DOCS_MAN= src/lib/client/api.mandocdir/man.3oc \ src/lib/server/api.mandocdir/man.3os \ src/ocamlbuild/api.mandocdir/man.3o doc: $(BUILDER) $(BUILDER) $(DOCS_HTML) wikidoc: $(BUILDER) $(BUILDER) $(DOCS_WIKI) man: $(BUILDER) $(BUILDER) $(DOCS_MAN) alldoc: man wikidoc doc ### Testing ### .PHONY: run.local run.opt.local links run.local: tests.byte fifo tests/eliom.conf OCAMLPATH=tests/:$(OCAMLPATH) ocsigenserver -c tests/eliom.conf run.opt.local: tests.opt fifo tests/eliom.conf OCAMLPATH=tests/:$(OCAMLPATH) ocsigenserver.opt -c tests/eliom.conf tests.byte: links ${MAKE} -C tests byte tests.opt: links ${MAKE} -C tests opt links: -mkdir -p local/var/run -mkdir -p local/var/log -mkdir -p local/var/lib -mkdir -p local/tmp fifo: [ -p local/var/run/eliom_command ] || \ { mkfifo local/var/run/eliom_command; \ chmod 660 local/var/run/eliom_command; } ### Cleaning ### .PHONY: clean clean.local distclean clean: clean.local ocamlbuild -quiet -no-plugin -clean ${MAKE} -C tests clean clean.local: -rm -f eliom-*.tar.gz distclean: clean clean.local ${MAKE} -C tests distclean -find ./ -name "*\#*" | xargs rm -f ### Installation #### .PHONY: install uninstall reinstall install uninstall: eliom.install ifneq ($(PREFIX),) opam-installer --$@ --prefix $(PREFIX) eliom.install else @echo you must provide a prefix with : make PREFIX=myprefix $@ endif reinstall: ${MAKE} uninstall ${MAKE} install eliom-4.2/README000066400000000000000000000026661255347715300133720ustar00rootroot00000000000000Eliom ------------------------------------------------------------------ Requirements: ============= * See `opam` ------------------------------------------------------------------ Build instructions: =================== We recommand to use the opam package manager to install Eliom. If you want to compile manually: * run "make" to compile * run "make PREFIX=yourprefix install" as root to install * run "make PREFIX=yourprefix uninstall" to uninstall everything ------------------------------------------------------------------ Local testings: =============== * install eliom * run "make run.local" of "make run.opt.local" in the ocsigen source directory. * open http://localhost:8080/miniwiki in your browser * if it does not work, look at the logs (see 'local/var/log/' in the ocsgigen source directory) or run ocsigen with options -v or -V (verbose and debug mode). * sources for this example may be found in the directory 'tests/miniwiki'. For a full tutorial, see: http://ocsigen.org/tutorial For testsuite, see: http://localhost:8080/ ------------------------------------------------------------------ Authors: ======== Vincent Balat Jérôme Vouillon Grégoire Henry Pierre Chambart Benedikt Becker Boris Yakobowski Hugo Heuzard Raphaël Proust Stéphane Glondu Gabriel Kerneis Denis Berthod Jaap Boender Simon Castellan Mauricio Fernandez Archibald Pontier Simon Castellan Jacques-Pascal Deplaix eliom-4.2/README.build000066400000000000000000000015011255347715300144530ustar00rootroot00000000000000== internal description of compilation/installation steps 1 - build custom ocamlbuild (build/build.native) this custom ocamlbuld uses src/ocamlbuild/ocamlbuild_eliom.ml to avoid duplication 2 - call `ocaml pkg/build.ml` (topkg) that will call the custom builder (from 1) to build request targets 3 - eliom.install is generated and can be used by opam-installer == How to update the build system - add new files => update pkg/filelist.ml client only files can be : src/lib/client/*.ml, src/lib/*.client.ml server only files can be : src/lib/server/*.ml, src/lib/*.server.ml common files can be : src/common/*.ml, src/*.eliom (with shared_section) - add packages requirement => update pkg/META (if needed) and src/_tags "package(new_package)" - change version update VERSION and pkg/META eliom-4.2/VERSION000066400000000000000000000000061255347715300135440ustar00rootroot000000000000004.2.0 eliom-4.2/_tags000066400000000000000000000000441255347715300135160ustar00rootroot00000000000000"tests":-traverse "local":-traverse eliom-4.2/build/000077500000000000000000000000001255347715300135775ustar00rootroot00000000000000eliom-4.2/build/_tags000066400000000000000000000001051255347715300146130ustar00rootroot00000000000000<*.{ml,byte,native}>:package(unix,ocamlbuild,js_of_ocaml.ocamlbuild) eliom-4.2/build/build.ml000066400000000000000000000062411255347715300152330ustar00rootroot00000000000000open Ocamlbuild_plugin module Pack = Ocamlbuild_pack module Conf = struct let server_dir = "server" let client_dir = "client" let type_dir = "type_dir" end module Intern = struct let with_package = function | "eliom.syntax.type" -> "pkg_pa_eliom_type_filter" | "eliom.syntax.client" -> "pkg_pa_eliom_client_client" | "eliom.syntax.server" -> "pkg_pa_eliom_client_server" | "eliom.syntax.predef" | "eliom.client" | "eliom.server" -> (* do noting in this case *) "pkg_dummy" | _ -> assert false end module Eliom_plugin = Ocamlbuild_eliom.MakeIntern(Intern)(Conf) let _ = dispatch (fun x -> Eliom_plugin.dispatcher x; match x with | After_rules -> Doc.init (); let link source dest = rule (Printf.sprintf "%s -> %s" source dest) ~dep:source ~prod:dest (fun env _ -> Cmd (S [A"ln"; A"-f";P (env source); P (env dest)])) in (* add I pflag *) pflag [ "ocaml"; "compile"] "I" (fun x -> S[A"-I"; A x]); pflag [ "ocaml"; "infer_interface"] "I" (fun x -> S[A"-I"; A x]); pflag [ "ocaml"; "doc"] "I" (fun x -> S[A"-I"; A x]); (* add syntax extension *) let add_syntax ?needs name path = let _S l = match needs with | None -> S l | Some p -> S (A "-ppopt":: P p ::l) in (* hack : not dep when "compile" to avoid the extension syntax to be link with binaries *) (* the dep with ocamldep make sure the extension syntax is compiled before *) flag ["ocaml";"compile";"pkg_"^name] (_S [A "-ppopt" ;P (path ^ name -.- "cmo") ]); flag_and_dep ["ocaml";"ocamldep";"pkg_"^name] (_S [A "-ppopt" ;P (path ^ name -.- "cmo") ]); flag_and_dep ["ocaml";"infer_interface";"pkg_"^name] (_S [A "-ppopt" ;P (path ^ name -.- "cmo") ]); flag_and_dep ["doc";"pkg_"^name] (_S [A "-ppopt" ; A"-printer"; A"-ppopt";A "o"; A "-ppopt" ; A"-parser"; A"-ppopt";A "o"; A "-ppopt" ;P (path ^ name -.- "cmo") ]) in add_syntax "pa_include" "src/syntax/"; pflag ["compile"] "sig_inc" (fun d -> S[A"-ppopt";A"-sig-inc";A"-ppopt";A d]); pflag ["ocamldep"] "sig_inc" (fun d -> S[A"-ppopt";A"-sig-inc";A"-ppopt";A d]); pflag ["infer_interface"] "sig_inc" (fun d -> S[A"-ppopt";A"-sig-inc";A"-ppopt";A d]); pflag ["ocaml";"doc"] "sig_inc" (fun d -> S[A"-ppopt";A"-sig-inc";A"-ppopt";A d;]); add_syntax "pa_eliom_seed" "src/syntax/"; let needs = "src/syntax/pa_eliom_seed.cmo" in add_syntax ~needs "pa_eliom_client_client" "src/syntax/"; add_syntax ~needs "pa_eliom_client_server" "src/syntax/"; add_syntax ~needs "pa_eliom_type_filter" "src/syntax/"; (* link executable aliases *) let link_exec f t = link (Printf.sprintf "src/tools/%s.byte" f) (Printf.sprintf "src/tools/%s.byte" t); link (Printf.sprintf "src/tools/%s.native" f) (Printf.sprintf "src/tools/%s.native" t); in List.iter (link_exec "eliomc") [ "eliomopt";"eliomcp";"js_of_eliom"]; link_exec "distillery" "eliom-distillery"; | _ -> ()) let _ = Options.make_links:=false; Options.plugin := false; Options.use_ocamlfind := true; Ocamlbuild_unix_plugin.setup (); Ocamlbuild_pack.Main.main () eliom-4.2/build/doc.ml000066400000000000000000000037201255347715300147000ustar00rootroot00000000000000open Ocamlbuild_plugin module Pack = Ocamlbuild_pack (* Doc should move in its own ocamlbuild plugin *) (* Compile the wiki version of the Ocamldoc. Thanks to Till Varoquaux on usenet: http://www.digipedia.pl/usenet/thread/14273/231/ *) let ocamldoc_wiki tags deps docout docdir = let tags = tags -- "extension:html" in Ocamlbuild_pack.Ocaml_tools.ocamldoc_l_dir tags deps docout docdir let ocamldoc_man tags deps docout docdir = let tags = tags (* -- "extension:html" *) in Ocamlbuild_pack.Ocaml_tools.ocamldoc_l_dir tags deps docout docdir let init_wikidoc () = try let wikidoc_dir = let base = Ocamlbuild_pack.My_unix.run_and_read "ocamlfind query wikidoc" in String.sub base 0 (String.length base - 1) in Ocamlbuild_pack.Rule.rule "ocamldoc: document ocaml project odocl & *odoc -> wikidocdir" ~insert:`top ~prod:"%.wikidocdir/index.wiki" ~stamp:"%.wikidocdir/wiki.stamp" ~dep:"%.odocl" (Ocamlbuild_pack.Ocaml_tools.document_ocaml_project ~ocamldoc:ocamldoc_wiki "%.odocl" "%.wikidocdir/index.wiki" "%.wikidocdir"); flag ["wikidoc"] & S[A"-colorize-code";A"-i";A wikidoc_dir;A"-g";A"odoc_wiki.cma"]; pflag ["wikidoc"] "subproject" (fun sub -> S [A"-passopt";A "-subproject"; A sub]) with Failure e -> () (* Silently fail if the package wikidoc isn't available *) let init_mandoc () = Ocamlbuild_pack.Rule.rule "ocamldoc: document ocaml project odocl & *odoc -> mandocdir" ~insert:`top ~prod:"%.mandocdir/man.%(ext)" ~stamp:"%.mandocdir/man.%(ext).stamp" ~dep:"%.odocl" (Ocamlbuild_pack.Ocaml_tools.document_ocaml_project ~ocamldoc:ocamldoc_man "%.odocl" "%.mandocdir/man.%(ext)" "%.mandocdir"); pflag ["apiref"] "man_ext" (fun ext -> S[A"-man-mini";A "-man-section"; A ext; A"-man-suffix";A ext]) let init () = init_wikidoc (); init_mandoc (); (* ocamldoc intro *) pflag_and_dep ["doc"] "with_intro" (fun f -> S [A "-intro"; P f]); eliom-4.2/doc/000077500000000000000000000000001255347715300132455ustar00rootroot00000000000000eliom-4.2/doc/client.indexdoc000066400000000000000000000004501255347715300162410ustar00rootroot00000000000000{1 Eliom client API} {!modules: Eliom_pervasives Eliom_lib Eliom_client } {2 Content and form creation} {!modules: Eliom_content.Html5 Eliom_content.Svg Eliom_content.Xml } {2 Client/server communication} {!modules: Eliom_service Eliom_bus Eliom_comet Eliom_react } {2 Index} {!indexlist} eliom-4.2/doc/index.wiki000066400000000000000000000005241255347715300152420ustar00rootroot00000000000000= Eliom -- API reference [[wiki:mindmap.pdf|A mindmap to get an overview on the most important modules of Eliom]] <<| in /var/www/data/site-ocsimore/eliom >> <> <> <> eliom-4.2/doc/manual-wiki/000077500000000000000000000000001255347715300154635ustar00rootroot00000000000000eliom-4.2/doc/manual-wiki/clientserver-applications.wiki000066400000000000000000000160251255347715300235450ustar00rootroot00000000000000= Programming client-server applications with Eliom <> >> == General principles === What is a client/server Eliom application An Eliom application is a distributed application that runs partly on the server, partly on a browser. The program is fully written in OCaml, with a syntax extension to distinguish between server and client code. Both parts are extracted during the compilation process, the server part is compiled as usual for an Eliom website, and the client part is compiled to Javascript to be run in the browser. An intersting feature of Eliom applications is that the client side process does not stop when you click on a link or send a form, and it is possible to keep the traditional Web interaction (with URLs, bookmarks, back button, etc). For example if the page is playing music, it won't stop when the user continue his visit on the Web site. Client side parts are using {{{Lwt}}} for concurrency, making possible to have concurrent programs in the browser very easily. As both parts are implemented in OCaml, it is very easy to use client side OCaml data on server side, and vice-versa. Eliom handle the communication between client and server automatically in both direction. For example it possible to use a server-side variable in the client program. Eliom also implements an "HTTP-push" mechanism, allowing the server to send messages to a client. Client-side parts of the program can use most Eliom features, exactly as usual, for example to create HTML, or links, forms from services. On server side, it is possible to save data (some state) for each client process (that is, one tab in a browser), simply by using Eliom references with scope {{{`Client_process}}}. You can register services for one client process, or even set cookies for one tab. === How it works The code of an Eliom application is written in OCaml, with <> to distinguish between server and client code. The files using this syntax usually have the extension {{{.eliom}}}. As the compling process is quite complex, we provide commands called {{{eliomc}}} and {{{js_of_eliom}}} that does everything for you (separating client and server parts, calling {{{ocamlc}}}, {{{js_of_ocaml}}}, etc). Services belonging to the application are registered using the module {{{Eliom_registration.App}}}. More precisely, this is a functor that needs to be applied for each application you create. These services just return HTML5 pages as usual (using {{{Eliom_content.Html5}}}) The client side program (compiled in JavaScript) is added automatically by Eliom, with all its data, and run automatically when the page is loaded. Module <> provides some useful functions for client side programming with Eliom: e.g. <> for switching to another page. Module {{{Eliom_comet}}} allows for the server to send notifications to the client (even if the client is not explicitely doing a request). Use module {{{Eliom_react}}} to make client-server reactive programming (using the React external library). === The App functor For each Eliom application, you must create a service registration module by applying the {{{App}}} functor: <> the {{{application_name}}} parameter is the name of the javascript file containing the application. Then you can do for example: < Lwt.return (html (head (title (pcdata "Hi!")) []) (body [p [pcdata "Hey."]]))) >> Eliom will add automatically the required headers to send the client side program and all its data. == Application, life and death When an user enters the page of a service registered by an application module (created with the {{{App}}} functor), the application is started. During the life of the application, a single OCaml program will run on the browser: Lwt threads will keep running, global variables will stay available, etc. until the application is closed. The application will keep running when the user clicks on links to pages inside the same application. This application will be closed when: * the user closes the browser tab containing the application, * the user goes to a page outside of the application, * the user changes the current url by another mean than the application interaction (reload the page with {{{F5}}}, manual typing of URL, ...), * the application call the {{{Eliom_client.exit_to}}} function. It is possible to prevent the application from starting when visiting an application page by setting the {{{do_not_launch}}} to {{{true}}} at the service registration: < Lwt.return (html (head (title (pcdata "Hi!")) []) (body [p [pcdata "Hey."]]))) >> That way, you can delay the javascript loading until it is really needed. Visiting a service registered with {{{do_not_launch=true}}} will not stop a running application. By default, every link of form towards another service of the same application is reimplemented by Eliom so that it does not stop the application. Instead of asking the browser to load a new page, Eliom does an XML HTTP request (XHR). But you can avoid this and insert regular links or forms by adding the optional parameter {{{~xhr:false}}}. This will force reloading the application when the link is clicked. === Navigating in and out of the application. Two functions are available on client side to change the current page without interaction from the user. The function <> goes to the service taken as parameter. If the service is in another application or not in an application it will stop the current one. The function <> opens an Eliom service in a new browser window (cf. Javascript's ##window.open##). <> changes the current page and always leaves the application. == Using Eliom on client side <> == Misc == === Leaving application and going back Usually, when going to an application page, a new client process is launched on the server, but there are situations where an old client process is used instead: Browsers tend to take the result from their cache when using the back button even if the page was marked (by HTTP headers) as non-cacheable. eliom-4.2/doc/manual-wiki/clientserver-communication.wiki000066400000000000000000000303031255347715300237170ustar00rootroot00000000000000=@@id="communication"@@ Communication between the client and the server <> >> Besides values passed by the mean of the {{{%variable}}} syntax, there are multiple ways for the client and server to exchange values. ==@@id="rpc"@@ Remote Procedure Calls Eliom provides you an easy way to call server functions from the client: <> (and on <>). A function ##'a -> 'b Lwt.t## can me wrapped on the server side by <>. When the result is sent to the client, it appears as a plain function ##'a -> 'b Lwt##. It is necessary to provide an instance of <> for the argument type, to safely send the argument from the client to the server. Every call to ##server_function## creates a new non-attached POST coservice. It is thus advisable to apply it only once and bind it to an identifier, if it is to be used several times. Example: < log }} {client{ let () = Eliom_client.onload (* NB The service underlying the server_function isn't available on the client before loading the page. *) (fun () -> Lwt.async (fun () -> %rpc_log "hello from the client to the server!")) }} >> Exceptions raised in the server-side function cannot be handled directly on the client (because it's impossible to marshal them in OCaml to send it to the client). Instead, if an exception is raised in the server function, the function application fails (in Lwt) on the client with the exception <> whose argument describes the original exception (according to {{{Printexc.to_string}}}). == Client requesting data Server function are implemented using special services taking and returning OCaml values. In this section we will see how to define services returning OCaml data. These services are registered using <> and can be called using <>. Those services cannot be visited by the browser as web pages. You usually want POST coservices for this use. This corresponds to remote function calls, that are typically handled by non-attached POST coservices. Example of use: < Lwt.return 3.1415926535) let _ = My_appl.register_service ~path:["pi"] ~get_params:Eliom_parameter.unit (fun () () -> ignore {unit{ Lwt.ignore_result( lwt pi = Eliom_client.call_ocaml_service ~service:%pi_service () () in Lwt.return ( Dom_html.window##alert(Js.string ("pi = "^(string_of_float pi))))) }}; Lwt.return Html5.D.(html (head (title (pcdata "pi")) []) (body []))) >> Since client and server side value representation are not the same, it is not possible to send any Ocaml value, the restriction on what can be sent are the same as for the {{{%variable}}} mechanism (see the <>). ==@@id="client_sending_data"@@Client sending data The client can send OCaml values as parameters to services. To do that, declare the expected parameter type using <>. Since the server can't trust the client to send correcly formed data, Eliom is not using the standard OCaml marshalling mechanism (the server needs to be able to check that the value is of the expected type). For this reason, you must declare the types of the data you want to be able to send to the server using the {{{Deriving}}} syntax extension: <> This type can now be used as a parameter for a service: <) (fun () v -> Lwt.return Html5.D.(html (head (title (pcdata "title"))) (body [ match v with | A _ -> pcdata "A" | B _ -> pcdata "B" ]))) let _ = My_appl.register_service ~path:["s2"] ~get_params:unit (fun () () -> Lwt.return Html5.D.(html (head (title (pcdata "title"))) (body [ [p ~a:[a_onclick {{ ignore (Eliom_client.change_page ~service:%s (A (1,["s"])) ()) }}] [pcdata "Click to send Ocaml data"] ]]))) >> It works for the data types you define, and the data types from OCaml's standard library. For types defined in third third party libraries, have a look at deriving's [[href:http://code.google.com/p/deriving/wiki/Introduction|documentation]] and Js_of_ocaml's <>. <> == Server sending data Eliom implements some mechanisms to make possible for the server to send data to a client. We call that mechanism //Comet//, it is also sometimes called //HTTP push//. The simple low level version above which all other following mechanisms are implemented is provided in the <> module. Comet defines channels which can convey data. A channel is created using a Lwt stream. It is a kind of cooperative lazy list. The two main methods to create a stream are through the functions <> and <>. < 'a option Lwt.t) -> 'a t val create : unit -> 'a t * ('a option -> unit) >> Function <> makes possible to create a stream where a new value is added each time a function returns. Function <> returns a stream and a function to push new values to the stream. On client side the type <> is just a Lwt stream <>. There are 3 kind of channels depending on how you want to send data. * Channels created with <> have a buffer with a limited size. Message are read from the stream as soon as they are available, i.e. for stream created with <>, that means that the function is called another time as soon as the previous one terminate. For stream created with <>, this is as soon as they are pushed. If the client missed too much messages (more than the size of the buffer) it will receive an exception <> when reading data from the stream. * Channels created with <> have no buffering and can loose messages, but the client will always receive the last value: For instance if many messages are sent in a short time, the client may receive only the last one. Those channels never raise <>. * Channels created with <> consume data on the stream only when their is a request from the client. Channels can be closed on client side by cancelling a thread waiting for data on it. Like services, channels have a scope (only site or client process). The constraints vary with respect to the scope you choose: * Channels created with scope <> or using <> are stateless channels: the memory consumption does not depend on the number of users requesting data on it. When the channels are not reachable from the server code, they are garbage collected and closed. Named stateless channels can be accessed from <>. * Channels created with scope <> must be created inside a service handler. They are assigned to a particular client process. Different channels created with the same stream do not share memory. They are closed when requested or when the client process is closed. It is possible to know when a client stop requesting data on those channels using <>. //Warning:// Be careful about memory consumption when using client process channels. === Comet configuration The server can push data to a client only when the client has an open HTTP connection waiting for answer. As of now, a comet request can only last at most 10 seconds. After that, the client can either do a new request or stale for some time: this is the activity behaviour. This can be configured on client side, using the functions from <> For instance if you receive data which doesn't need frequent update, you could set the time between different requests quite high and stop requesting data as soon as the browser looses the focus. <> If you need more reactivity for a few seconds, do: <|= (fun () -> drop_configuration fast_c)) >> The original setting will be reset after the drop. == Reactive values A common usage of comet is for the server to update a value available on client side. A convenient way to implement this is to use reactive programming. Eliom provides a reactive interface for channels, using Daniel Bünzli's React library. To share a React event or signal with the client, use functions <> or <> On client side the value returned by those functions is directly a React event or signal. The contrary is also available using <>. Since this is implemented using comet, tunnig comet configuration will also affect the behaviour of shared react variables. == Client-Server shared bus It is cometimes useful to have a bidirectionnal channels shared between multiple clients. This is the purpose of buses. Those are created using <>. Since the server will also receive data on the bus, the description of the type (using deriving) is needed to create a bus. Like comet channels, the behaviour of buses can be tuned using the module <>. There are additionnal configurations available on buses to tune the client side buffering. ==@@id="cors_channels"@@ Another Server sending data (Comet on another server) It is possible to access a named stateless channel created on another server. It has to be declared using <>. The declaration of the channel must match exactly the creation. The server generating the page and the server that created the channel must run exactly the same version of Eliom. By default a browser can't do requests to a different server, to allow that the server serving the channel must allow Cross-Origin Resource Sharing using the <>. eliom-4.2/doc/manual-wiki/clientserver-html.wiki000066400000000000000000000500231255347715300220170ustar00rootroot00000000000000=@@id="server_generating_html"@@Generating HTML pages= Ocsigen provides several ways to generate and type HTML5 pages. * The default technique to produce HTML5 pages using Eliom are the <>, <> and <> modules. It is the only one supported for client-server Eliom programs. This module provides a typing based on OCaml's polymorphic variants, which ensures at compile time, that the pages you will generate will respect the recommendations of the W3C (or be very close). * It is also possible to use a syntax extension to write your pages with the usual HTML syntax. This solution is also typed with polymorphic variants and is compatible with the previous one. * You can also choose to generate untyped html as text. The types in OCaml closest to XML types are //polymorphic variants//. Ocsigen uses them to provide a module with very good HTML5 typing. The full documentation is available <>. <> >> == Generating HTML for Eliom applications === The TyXML library vs. the DOM API On client side there are two kinds of HTML representations: one is based on the <> and the other one is the browser DOM tree accessible through Js_of_ocaml modules <> and <>. The TyXML representation is a OCaml immutable typed tree. The DOM tree is mutable structure manipulated using the browser API which permit the modification of the displayed page. In the DOM represention adding a node as a child to an other node removes it from its previous ancessor. Since those representation does not behave at all the same way, they are not used for the same thing. * It is far easier and safer to describe content using TyXML, but it is not possible to add a TyXML element to the page without explicit conversion to the DOM representation. * The TyXML representation has the same interface on client and server side. This allows share code between server and client. * Dom manipulation is heavy: to build some part of a tree, one needs to create each node separately then append them to their parents. For example, here is a {{{div}}} element built with TyXML and then converted to the DOM representation using the module << a_api subproject="client" | module Eliom_client.Html5 >>: <> And here the same built using the DOM API: <> To ease the DOM manipulation on the client, the usual DOM manipulation function are also available on TyXML elements. See section the next section for HTML5 element manipulation, by value and by reference. ===@@id="unique"@@ HTML5 element manipulation, by value and by reference There are four modules to create typed HTML: {{{Eliom_content.Html5.F}}}, {{{Eliom_content.Html5.D}}}, {{{Eliom_content.Html5.R}}} and {{{Eliom_content.Html5.C}}}. The last one is for reactive elements and is addressed in another section. It is possible to mix the four kinds of nodes in the same page. Elements built with {{{Eliom_content.Html5.F}}} are sent by value, while elements built with {{{Eliom_content.Html5.D}}} are sent to the client by reference. Eliom adds an identifier as attribute of {{{D}}} elements to make it possible to find them back in the page from client side. <> Sending elements by reference allows easy manipulation of elements included in the initial html document from event handlers, as the {{{input}}} element in the following example. < let open Eliom_content.Html5.D in let input = input ~a:[a_input_type `Text] () in let onclick_handler = {{ let v = Js.to_string (Eliom_client.Html5.of_input %input)##value in Dom_html.window##alert(Js.string ("Input value :" ^ v)) }} in let button = button ~a:[a_onclick onclick_handler] [pcdata "Read value"] in Lwt.return (html (head (title (pcdata "Test")) []) (body [input; button]) ) ) >> In this example, if the input button would have been incorrectly sent by value, two different input fields would have been created: one displayed in the document and one referenced from the event handler. The latter will always contains an empty value. There are still two situations where sending elements by value is still required: * one want to have multiple occurences of the same elements in the document. Indeed, elements sent by reference follow the DOM semantics where an element have only one instance in current document. For example, the following list will contains a single element:\\ \\ {{{let li = li [pcdata "Shared item"] in ul [li; li; li;] }}}. * one have a large page with a lot elements. Handling elements by references add a small overhead while loading the page, around 50ms per 1000 elements on a not so fast computer. In any case, it is possible to mix elements sent by references and elements sent by value in the same document. By default, a reference on an element is only valid in the current HTTP request: hence, sending an element built with {{{Eliom_content.Html5.D}}} in two different pages will produce two distinct nodes. If you want to define a element reference that is preserved accross the different page of an application, you must explicitely name this element with the function <>, that takes as parameters an element identifier and a non named element. Element identifiers are created with the function <>. See also section <>. The module <> allows using the classical DOM manipulation functions (e.g. appendChild, addEventlistener, ...) directly on the identifier of an HTML5 elements. ===@@id="reactive"@@Reactive DOM {{{Eliom_content.Html5.R}}} allows one to insert time varying values into the DOM tree. It relies on React's signal {{{'a React.signal}}}. More information about react can be found on the [[http://erratique.ch/software/react| homepage]]. The react nodes also use [[https://github.com/hhugo/reactiveData|ReactiveData]], which allows to manipulate lists of nodes in a reactive way. When dealing with dynamic content, one usally ends up with a lot of imperative DOM manipulations: replacing, appending, removing DOM elements, updating attributes, etc. {{{Html5.R}}} hides most of those imperative DOM operations. Every time a signal changes, the corresponding DOM tree updates itself. ==== Usage on client side To insert reactive DOM elements, just use module {{{Html5.R}}} instead of {{{Html5.D}}} or {{{Html5.F}}} for these elements. {{{Html5.R}}} makes also possible to define reactive attributes. Use function {{{Html5.R.node : 'a elt React.signal -> 'a elt}}} to insert a reactive node in a page. ===== Example < acc | n -> aux (s.[n - 1] :: acc) (pred n) in aux [] len let value_signal, set_value = React.S.create "initial" (* value_signal : string React.signal *) let value_len = React.S.map String.length value_signal (* value_len : int React.signal *) let content_signal : Html5_types.div_content_fun elt React.signal = React.S.map (fun value -> let l = split value in F.div ( List.map (fun c -> F.p [F.pcdata (Printf.sprintf "%c" c) ] ) l ) ) value_signal let make_color len = let d = (len * 10) mod 255 in Printf.sprintf "color: rgb(%d,%d,%d)" d d d let make_client_nodes () = [ D.p [R.pcdata value_signal]; D.p ~a:[ R.a_style (React.S.map make_color value_len)] [R.pcdata value_signal]; R.node content_signal ] }} let make_input () = let inp = D.Raw.input ~a:[a_input_type `Text] () in let _ = {unit{ Lwt_js_events.(async (fun () -> let inp = To_dom.of_input %inp in keyups inp (fun _ _ -> let s = Js.to_string (inp##value) in set_value s; Lwt.return ()))) }} in inp let main_service = Eliom_service.App.service ~path:[] ~get_params:Eliom_parameter.unit () let () = Testnodes_app.register ~service:main_service (fun () () -> let inp = make_input () in let cldiv = C.node {{ D.div (make_client_nodes ()) }} in Lwt.return (Eliom_tools.F.html ~title:"testnodes" ~css:[["css"; "testnodes.css"]] (body [F.h1 [pcdata "Reactive DOM"]; inp; F.h2 [pcdata "Client side reactive nodes:"]; cldiv; ]) )) >> ===@@id="inject"@@Dom & Client-values {{{Eliom_content.Html5.C}}} allows one to insert client-side content into server-side HTML5-trees. This makes possible, for example, to insert reactive nodes in a server-side generated page. ==== Example < Lwt.return (Eliom_tools.F.html ~title:"testnodes" ~css:[["css"; "testnodes.css"]] (body [ F.div ~a:[C.attr (client_reactive_attrib ())] [ C.node (client_reactive_title ()); ] )) >> Module C is also available on client-side, to make it possible to use it in shared sections. ===@@id="global"@@Global elements of an application Sometimes you may want to modify the content of an HTML element and to keep the element and its modified content when changing page. For example a {{{div}}} element which contains a chat box or a music player should be preserved while browsing across the different pages of your site. For this purpose, Eliom provides a notion of global element. Such elements are instantied only once for an application and that unique instance is used in every page that references the element. To create a global element, use function <>. < 'a elt >> In the following example, the content of {{{global_list}}} will be preserved when you click on the "reload page" link. < let page_number = incr cpt; string_of_int !cpt in let append_item = {{ let item_text = "item inserted in page #" ^ %page_number in let item = Eliom_client.Html5.of_li (li [pcdata item_text]) in Dom.appendChild (Eliom_client.Html5.of_ul %global_list) item }} in let append_link = a ~a:[a_onclick append_item] [pcdata "append item"] in Lwt.return (html (head (title (pcdata "Test")) []) (body [h1 [pcdata ("Page #" ^ page_number)]; p [append_link]; p [reload_link]; global_list]) ) ) >> Another use of global element is for external javascript that should be included in every page but must be executed only once in an application. In the following code snippet, the alert "global script" is displayed only once, while the alert "non global script" is display every time you click on the "reload page" link. < Lwt.return (html (head (title (pcdata "Global script example")) [ global_script; simple_script ]) (body [ p [reload_link] ]))) >> === HTML syntax extension=== <> Ocsigen also has a syntax extension for OCaml that allows you to write pages using HTML syntax (but you are free not to use it). This is convenient for example if you want to include (parts of) HTML pages that have been created by third party. To choose actual XML-implementation you have to provide a module named ##Html5## (or ##Svg## respectively): For example, the following code: <

plop

~>> >> is a caml value of type {{{Html5_types.html Html5.M.elt}}}. To compile a module containing this syntax, you need the camlp4 preprocessor: {{{ ocamlc -I /path_to/ocsigen/ -pp "camlp4o /path_to/ocsigen/xhtmlsyntax.cma -loc loc" -c your_module.ml }}} You can insert OCaml expressions of type {{{'a Html5.M.elt}}} inside html using {{{$...$}}}, like this: <Ocsigen >> in <<

$oc$ will revolutionize web programming.

~>> >> <<|wip| remove \ before $, _ in code, everywhere in pdf version!!!!!!!!!! >> You can insert OCaml expressions of type string inside html using ##$str:... $##, like this: <i is equal to $str:string_of_int i$

~>> >> If you want to use a dollar in your page, just write it twice. You can write a list of HTML5 expressions using the syntax {{{<:xmllist<...>>}}}, for example: <hello

~>> >> Here are some other examples showing what you can do: < $first_il$ $list:items$ ~>> >> Warning: lists antiquotations are allowed only at the end (before a closing tag). For example, the following is not valid: < $list:items$ $last_il$ ~>> >> The syntax extension is not allowed in patterns for now. //Warning:// The two syntaxes are not equivalent for typing. Using the syntax extension will do less checking. For example the following code is accepted but not valid regarding HTML5 standard (because <>> must contain a title): <

plop

~>> >> We recommend you use the functions from <>, as you will (almost) always get valid HTML5. Use the syntax extension for example to enclose already created pieces of HTML, and check your pages validity with the [[http://validator.w3.org/| W3C validator]]. ===@@id="text_html"@@Text HTML=== The last possibility is to use untyped HTML. Just build strings containing your pages. Here is an example: < Lwt.return ("n'importe quoi "^ (Eliom_content.Html_text.a coucou "clic" ())^ "")) >> Writing HTML as text makes applications much more difficult to maintain. We do not recommend this. ===@@id="custom_data"@@Custom data for HTML5=== Eliom provides a type-safe interface for using HTML5's custom data, <>. ==== Creation ==== Custom data may be created either from string-conversation functions by <> <> or by a Json-deriving type <> < }} >> ==== Injecting ==== Custom data can be injected into HTML5-trees of type <> by the function <>: <> NB, HTML5 gives no restriction on the usage of custom data, any custom data can may be added to //any// HTML5 element. ==== Reading/writing the DOM ==== On the client side, custom data can be read from and written to JavaScript DOM elements of type <>. Custom data can be read from a DOM-element with the function <>. If no respective custom data attribute can be found in the element * the ##default## value from creating the custom data is returned, if any, or * an exception ##Not_found## is raised, otherwise. The custom data of a DOM-element can be set with the function <>. < let i = Html5.Custom_data.get_dom div coord_data in debug "{x=%d; y=%d}" i.x i.y; Html5.Custom_data.set_dom div coord_data { x = i.x + 1; y = i.y - 1 } }} >> ==== Default value ==== If a custom data is created with the optional argument ##default##, calls to <> return that instead of throwing an exception [Not_found]. < >> eliom-4.2/doc/manual-wiki/clientserver-language.wiki000066400000000000000000000247761255347715300226560ustar00rootroot00000000000000= Eliom's language extensions Use extension {{{.eliom}}} for the files belonging to a client-server Eliom application. Use extension {{{.eliomi}}} for the corresponding interface. By using this naming conventions, the programs {{{eliomc}}} and {{{js_of_eliom}}} will be using Eliom's syntax extension automatically. These syntax extensions make much easier to write client-server applications in a very concise style. They are described in this chapter. <> >> == Server, client, and shared-sections Server, client, and shared-sections make possible to write the code of the server and client parts in the same source file, and also to defined sections of the code that are common to the two sides. Some special brackets make possible to distinguish between client and server code: <> or no brackets for //server side code//, <> for //client side code//, and <> for some code that is //common to client and server parts//. This means that the corresponding sections are compiled only for the server and/or the client program. == Injecting server values into the client code Structuring the source code of your application into client and server sections wouldn't be of much use as it; we need a possibility to exchange data between those parts in a way which reflects the asymetries between the client and the server parts, i.e. that the client program is sent and initialized by the server program. Thus to ease the direct exchange of values between server and client, it is possible to access any server side, top level variable in a subsequent client section by just prefixing it with a %-sign. This is called //injecting// a server value into the client: <> The server side value is injected once and for all when the page is sent for the first time. There is no automatic request to the server whan the client tries to access this value. In particuler, if the server side value is mutable, a copy is sent to the client. == Server side client values On the other hand, it is possible to declare and deal with arbitrary client values in the server program. Those are just arbitrary expressions of client-side code declared inside double curly braces: <> If {{{expr}}} has type {{{typ}}} on the client, the resulting client value has the type {{{typ client_value}}} which is //abstract on the server//. But once it is sent to the client, it evaluates to the value of {{{expr}}} having type {{{typ}}}. <> ==== Injections Again, variables from the context of the client value may be injected to it by prefixing them by a %-sign. This is for example reasonable to inject a parameter into a request client value: < ignore {unit{ Eliom_lib.alert "Hello %s!" %name }}; Lwt.return html) }} >> The pattern used in this example is very common to ask the client side program to execute a piece of code after receiving the page. ====@@id="evaluation"@@ Evaluation Server side client values may occur in a //request// position, i.e. they are created during the processing of a request: < let v = {Js.string{ Js.string "another client side string" }} in Lwt.return html) >> Or they occur either in a //global position//, i.e. they are created while launching the server: <> All global client values are sent with the initial request of a client process. They are evaluated during the initialization of the client program, i.e. //before// setting up the document. This is necessary in order to safely inject them into the next client-section. Thus, if you want to refer the DOM in global client values (e.g. by injecting variabels holding Html5-elements) you must be sure to delay this by using <>. Request client values, however, are sent with the next response to the client and evaluated //after// setting up the (possibly) sent document. ==== Sending client values There are several ways how a server side client value can be sent to the client, accessing its concrete value. Firstly, the most basic one is by just injecting it to another client value: < let v = {int{ 42 }} in (* v is abstract *) ignore {unit{ Eliom_lib.alert "It's %i!" %v (* %v is 42 here ! *) }}; Lwt.return html >> In the above example, first a client value {{{v}}} (with the abstract type {{{int client_value}}}) is declared. Then a second client of type {{{unit}}} value is created. The injection {{{%v}}} has then the concrete value {{{42}}}. Here, the second client value is ignored; however, it will be evaluated on client side, executing the side effect, just because it has been created. A very neat way to do client side programming inside the service handler! Secondly, client values of type {{{(Dom_html.event Js.t -> unit) client_value}}} can be used as event handler in the construction of Eliom Html5 elements: < Eliom_lib.alert "Thanks." }} in let div = div ~a:[a_onclick onclick] [pcdata "Click me!"] in Lwt.return (html head [div]) }} >> Note here, how the type annotation of a client value can be omitted if the type of the client value is inferable from //its usage in the server code// (as the argument to {{{on_click}}} in the example). Thirdly, global client values can also be injected into the client section. == Restrictions to injections into the client values/sections It is not possible to send values containg closures that way. There are two executables: one on server side, and one one on client side, and closures just contains a pointer to the code. Extra code is never sent dynamically on the network. This means that unforced lazy values, objects, or anything containing functions can't be send. Functions must be defined on the side(s) where they will run. Most of the time, you can do all that you want by using client-values or server-functions. Some eliom types use a specific mechanism to circumvent this limitation. This is the case of: services, comet channels and buses. To use this mechanism see chapter <>. Those values are typechecked "by name": the most general type of a variable is inferred for server side then use as a type constraint on client side. For instance <> can be read as <> As client and server code are compiled separately, this means that a code like the following would be incorrect but would typecheck. < Dom_html.window##alert(Js.string s) }} >> Note that for some reason, it is impossible to use the {{{ {...{ }} }}} and {{{ {{ }} }}} syntax inside a module. For {{{ {{ }} }}} you can usually circumvent this limitation by declaring a function at toplevel with all the {{{%variable}}} as parameters. ==@@id="implementation"@@ Technical Documentation: Implementation of the language extensions //Do not read this section if you do not feel the urgency to dive deeply into the implementation details of Eliom, or if you have a weak stomach!// This sections gives some details on the implementation of the <>. To investigate this in more details, it is advisable to dump the source code for the server or client program with with ##eliomc -c -infer## or ##js_of_eliom -c -infer## respectively, and to refer to the API of the generated functions in ##Eliom_service.Syntax_helpers## on the server and ##Eliom_client.Syntax_helpers## on the client. === Client values For each occurrence of a client value ##{typ{ exp }}## with injected variables ##v_1##, ..., ##v_n## in the source code, i.e. static occurrence, at a location ##p##, the syntax extension registers with ##p## as the closure ID a function < exp' >> where ##exp'## is ##exp## with occurrences of ##%v_i## replaced by ##v'_i## where all ##v'_i## are free in ##exp##. When a client value is then created dynamically, a <> is registered to be sent to the client with the <> or <> respectively. It contains the closure ID, an instance ID (unique per client value), and the tuple of injected values (sometimes known as ##args##). On the client side, that client value datum will be used to register an actual client value: A client closure is obtained by the specific closure ID, and it is applied on the tuple of injected values. Finally, the result is registered in a client value table for that specific closure ID and instance ID. The representation of a client value on the server side is comprised just of the respective closure ID, and the instance ID. When it reaches the client, it is unwrapped to the concrete value by looking it up in the client value table mentioned before. === Injection The usage of an injection registers the value under a specific identifier on the server side. All injections are sent to the client with the initial request as a table mapping those identifiers to (untyped) values. On the client side, at the beginning of each client/shared section, all novel injections are registered in a global table of injections. This must be done post-hoc because client values are unwrapped late. The syntax extensions then generates for an injection just a lookup in that global table for its identifer. Type constraints are generated from the syntax extension. eliom-4.2/doc/manual-wiki/clientserver-mobile.wiki000066400000000000000000000014761255347715300223320ustar00rootroot00000000000000= Programming mobile applications with Eliom <> >> Eliom now has an experimental feature making possible to start the application from client side, making possible offline or mobile apps. As this feature is still very young, we still need to understand the needs of developers to improve it. If you try this, we would be happy to receive your experience reports. The experiments we did worked like this: * We used Phonegap or Cordoba * We provided a default index.html page, that includes the js generated by Eliom * The client side program calls new function <> to initialize the application, that is, mainly, set the default server that will be used in requests. More documentation soon ... eliom-4.2/doc/manual-wiki/clientserver-wrapping.wiki000066400000000000000000000137511255347715300227110ustar00rootroot00000000000000=@@id="wrapping"@@Wrapping = Reading of this chapter isn't mandatory for writing eliom application. It's worth a reading however before hacking in the eliom codebase. <> >> == Basics == The server side of Eliom can communicates to the client other kind of data than the raw XML contents of the pages. The wrapper mecanism is used to allow the browser side to access to the contents of variables declared on server side. For instance when we write <> the contents of the {{{text}}} variable is sent along the page for the client code to access it. Server side, when <> is executed, the variable {{{text}}} is registered into a table and an id is associated to it. This table will containt all the datas references by variables annotated with % in a page, and will be sent marshalled to the client. On client side the id will be used to retrieve {{{text}}}. Since all datas are sent in one table, if a variable is referenced multiples times, it will be sent only once, and sharing will be preserved: <> This code will display 42. After being sent, the client and server side values are distinct: the server side version of {{{a}}} won't be modified by the client side affectation and conversly the client side value won't change if {{{a}}} is changed later on server side. == Special types == === Custom wrappers === Usualy, client and server side values are represented the same way, and it is sufficient to only copy their content ( marshalled ) to the client. But certain types can't be transmitted this easilly: for instance, services. Those values must be transformed before marshalling: We need for this to use custom wrappers. This wrapping mechanism is defined in <>. Before sending, the values goes throught <> which transform marked values. A value marked is a value which have as its last field a value of type <>. For instance <> but not <> A wrapper is created by the <> function. It takes a function as parameter which will be called to transform the value during the wrapping. There is also a special wrapper <> which does nothing. It is usefull to stop calling the wrapper on a value: If there is still a wrapper in a value after its transformation, it will be called another time, potentially leading to an infinite loop. For instance < int | Value of int type wrapped_type = ( v * wrapped_type Eliom_wrap.wrapper) let wrapper = Eliom_wrap.create_wrapper (function | Value i,wrapper -> Value i, Eliom_wrap.empty_wrapper | Fun f,wrapper -> Value (f ()), Eliom_wrap.empty_wrapper) let v = ( Fun (fun () -> 1), wrapper ) let (v', empty_wrapper) = Eliom_wrap.wrap v>> At that time {{{v'}}} will be {{{Value 1}}}. Notice that <> does not enforce the output type of the wrapping function to be the same as the input type: Eliom_wrap is to be use with much caution! Do not use it if you don't understand how it works, it may lead to unpredictable segmentation faults and corrupted memory. === Custom unwrappers === We may also want to modify the value at unwrapping time. It is the case for instance of the type <>. On server side, it is transformed to a service, and the service is transformed to a function which call it on client side. To do this, we use custom unwrappers. A value is marked by an unwrapper the same way as with wrappers: A value is marked if its last field is a value of type <>. An unwrapper does not contain functions, it only contains an identifier of type <>. On client side a function can be registered to transformed values marked with an id: <>. < i + j ) let id = Eliom_client_unwrap.id_of_int marked_int_id let () = Eliom_client_unwrap.register_unwrapper id marked_int_unwrapper }} >> When the client will receive the value {{{v}}} it will transform it to {{{fun j -> j + 10}}} Thoses id are globals, take care of not using an existing one, you could for instance use the name of you type hashed as id. Consider those below 1024 to be reserved to Eliom internals. == Eliom types with predefined custom wrappers == The Eliom types that are marked are: * <> transformed to <> (but the client side representation) * <> transformed to <> * <> transformed to {{{ 'a -> unit }}} * <> transformed to {{{ 'a React.E.t }}} * <> transformed to <> eliom-4.2/doc/manual-wiki/config.wiki000066400000000000000000000371371255347715300176300ustar00rootroot00000000000000 = Compiling and configuring Eliom modules = <> >> This chapter explains how to compile Eliom module, how to set Eliom's options in the configuration file, and how to define options for your Eliom modules. See the Ocsigen server documentation for more information about the <>. ==@@id="misc"@@Using Eliom modules with Ocsigen server== ====Compiling Eliom modules If your application is server-side only, it is easy to compile an Eliom module (here {{{example.ml}}}) with the following command: {{{ ocamlfind ocamlc -thread -package eliom.server -c example.ml }}} or, in a shortest way: {{{ eliomc -c example.ml }}} ====Configuration file To run an Ocsigen server with an Eliom module {{{example.cmo}}}, add the following lines to Ocsigen's configuration file (<> most of the times): {{{            }}} The bloc surrounded by the {{{}}} tag creates a sub-site on your host, in directory {{{examples}}}. The {{{}}} tag is optional if you want to register your services at the root of the server path tree. The {{{}}} tag defines an Eliom module to be loaded (dynamically while starting Ocsigen server) for this subsite. ====Running Ocsigen server Run Ocsigen server, by typing the command {{{ ocsigenserver }}} or, if your configuration file is not in the default location: {{{ ocsigenserver -c //// }}} You should see the page corresponding to service {{{"coucou"}}} in site {{{examples/}}} at url\\ <>.\\ <}}} in the configuration file during the development process of your application. Thus, Ocsigen server will display the exceptions raised during the generation of a page in error pages. **Tip:** To debug your programs, add the option {{{-v}}} or {{{-V}}} of the {{{ocsigen}}} command to have verbose information on what succeeds during request. Also think to have look in the log files when something goes wrong!>> ===Several Eliom modules for one site=== If your site consists of several modules, you can load them consecutively from the configuration file using <>> (same syntax as <>>, the difference being that <>> does not generate any page). In that case, only the position of the <>> tag will be taken into account for generating the page using Eliom. Note that there can be only one <>> tag for each <>> (or <>>). ===Using findlib with Eliom modules=== If your module has a findlib <> file, it is also possible (and recommended!) to do: {{{            }}} ===@@id="reload"@@Updating sites without shutting down the server Ocsigen server has a feature that allows reloading the configuration without shutting down the server (see section * *). This can be used to reload Eliom modules without closing volatile sessions. To do that use <> for most of the distributions, or do it manually using: {{{ echo reload > /var/run/ocsigen_command }}} Only modules loaded inside <>>, <>> or <>> will be reloaded. Module loaded using <>> will not. Have a look at the logs to see if all went well during the reload. If something went wrong, old services may still be reachable. Warning: * Services created with the old modules or URLs that have not been masked by new ones will still reachable after the update! * During the reload, some information of the configuration file will not be re-read (for example port numbers, user and group, etc.). ==Interacting with Ocsigen server from Eliom programs ===Defining an exception handler for the whole site When an exception is raised during the generation of a page, or when the page has not been found or has wrong parameters, an HTTP error 500 or 404 is sent to the client. You may want to catch these exceptions to print your own error page. Do this using <>. Here is the handler used by the tutorial: < match e with | Eliom_common.Eliom_404 -> Eliom_registration.Html5.send ~code:404 (html (head (title (pcdata "")) []) (body [h1 [pcdata "Eliom tutorial"]; p [pcdata "Page not found"]])) | e -> fail e) >> ===Giving configuration options to your sites You can add your own options in the configuration file for your Web site. For example: < ... >> Use <> during the initialization of your module to get the data between <>> and <>>. <> ===@@id="static_linking"@@Static linking of Eliom modules From version 1.2, it is possible to link extensions and Eliom modules <>. But this is not straightforward. For Eliom modules, service registration and options setting must be delayed until the configuration file is read. To create a statically linkable Eliom module, use the function <>. It takes as parameters the name of the module and the initialization function, that will be called when the module is initialized in the configuration file. That function will register services (and possibly call <> if the module has configuration options). <> To initialize the module from the configuration file, use the syntax: {{{ ... }}} (or < ... >>) which is equivalent to: {{{ ... }}} (or < ... >>) with the exception that it does not load the module using <>, but calls the initialization function.\\ You can use functions like <> that needs some information about the site (here, volatile tables are associated to a site), only during a request or during the initialisation phase of the server. If you want to use that kind of function before the initialisation phase, for example if your module is linked statically with the server, you must call these function using the function <>. (One solution is to use a lazy value to delay the creation of the table, and force that value during the registration function). ===@@id="extensions"@@Advanced use: create an extension for the server that access Eliom's data If you want an Ocsigen extension with access to Eliom's data (for example if you want an extension that will register some services), you can use the function <> to register the function that will generate the <>. <> ==@@id="config"@@Global configuration options Here are Eliom's options you can use in configuration files. ===Timeouts <> Timeouts for states (and other states) can be set either inside tag {{{}}} (default value for all sites), or inside a {{{}}} tag (default for one site). Timeouts can also be modified programmatically using functions like {{{Eliom_state.set_global_volatile_timeout}}}, but by default these functions will not override configuration files. (see module <> for other functions). Thus, a website can set its own defaults and the user can still override them from the configuration file. If you want to set a timeout programmatically even if it has been modified in a configuration file, use the optional parameter {{{~override_configfile:true}}}. Timeouts can be set either for all scopes hierarchies, for one precise hierarchy, or for the default scope hierarchy. To do that programmatically, use the optional parameter {{{~scope}}}. To do that in configuration file, use the optional attribute {{{hierarchyname}}} (where an empty string value means default hierarchy). If this attribute is absent, the timeout will affect all states for which no other default has been set. The {{{hierarchyname}}} attribute exists only inside an {{{}}} tag (and not inside {{{}}}). The level attribute can take values {{{session}}} (browser) or {{{clientprocess}}} (tab). * {{{}}} The default timeout for volatile (in memory) states (value in seconds). {{{value="infinity"}}} means that the state will never finish. Note that each eliom module may set its own default, that will override this one. * {{{}}} Idem for persistent state data * {{{}}} Like {{{}}}, but for in memory data states only (not service states). * {{{}}} Like {{{}}}, but for service states only (not in memory data states). ===Garbage collector of states and services These options can appear inside tag {{{}}}. For now, it cannot be set for each site independently (tell us if you need that). * {{{}}} Time between two garbage collections of sessions, in seconds (default 3600). The value {{{"infinity"}}} means no GC of session. * {{{}}} Time between two garbage collections of persistent sessions, in seconds (default 86400.). The value {{{"infinity"}}} means no GC of session. * {{{}}} Like {{{}}}, but for service sessions only * {{{}}} Like {{{}}}, but for "in memory data" sessions only ===Limiting the number of sessions or coservices To prevent from denial of service, Eliom limits the number of sessions and the number of dynamic coservices. Without these limitations, it would be possible for an attacker to open repeatedly lots of sessions, or creating new services (for example CSRF safe coservices can create lots of coservices when you reload repeatedly a page). When the limit is reached, it is still possible to open new sessions or create new services, but the oldest session or service will disappear (the one that has not been used for the longest time). ====Limiting sessions First of all, there is a limitation of the number of sessions in a session group. The typical use of this is when an user opens several sessions from several computers. All the sessions belong to the same group (the group name is usually the user name). The limit is usually small (5 sessions per group by default). This limit is implemented for all kinds of sessions (service session, volatile and persistent data sessions). For persistent sessions, the implementation is not very efficient for very large limits. It is highly recommended to use session groups when possible. If you can't use session groups, the number of sessions is limitated by sub network for volatile sessions (service sessions and data sessions). The limitation is larger (default 1 million). The limit must be large enough, for example if the server is behind a reverse proxy, all incoming requests will come from the same IP address. Limiting by sub network instead of by IP address prevents attacks even if the attacker has a whole sub network available. The default mask for sub networks is {{{/16}}} for IPv4 and {{{/56}}} for IPv6. Some figures: If 1 session takes 1000 bytes (data + tables etc), 1 million sessions take 1 GB. If somebody opens 1000 sessions per second, then it will take 1000 s (16 minutes) to reach 1000000. It means that regular users will have their sessions closed after 16 minutes of inactivity if they share their sub network with someone doing an attack (or if the server is behind a proxy). For persistent sessions, there is no limitation per sub network for now. 1 billion sessions take 1 TB. If somebody opens 1000 sessions per second, then it will take 1 million s (16000 minutes = 266 h = 11 days) to reach 1TB. ====Limiting services The number of anonymous coservices is limited by session or by sub network if the service is registered in the global table. Default values: 1000 for one session, and 500000 for one subnet. Note that there is no limitation of named coservices or regular services. It is not a good practice to allow the creation of too much services of this kinds dynamically. ====How to set limits The limits and the subnet mask can be set programmatically by each module (for example to adapt the values to the size of session data) or in the configuration file (for example to adapt the values to the size of memory or network configuration) (see module <>). By default, functions like {{{Eliom_state.set_default_max_volatile_sessions_per_group}}} will not override a value set in the configuration file (but if you use {{{~override_configfile:true}}}). Thus, a website can set its own defaults and the user can still override them from the configuration file. The configuration file options can be set either inside the tag {{{}}} (global configuration), or inside the {{{}}} tag (configuration for each site). But the limits always are for one site (that is: a global limit value of 10 means 10 for each Eliom site). The syntax is: * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} * {{{}}} ==Per site configuration options === Disabling XHR-links By default, all links (##a##, ##form##) of an Eliom application are realized by Eliom's ##change_page## magic (unless their creation is augmented with ##~xhr:false##). In contrast, you may add the attribute ##xhr-links## into the content of the configuration of a Eliom module: {{{ ... }}} Then, all links that are not explicitely specfied as ##~xhr:true## are realized by their default HTTP behaviour. You can also set this value through the function <>. eliom-4.2/doc/manual-wiki/eliom-language.wiki000066400000000000000000000253631255347715300212470ustar00rootroot00000000000000= Eliom -- the language extensions In Eliom it possible to define the functionality of the server and the client program at in a single source file. The server program will constantly run on the web server. The client program will run independently in each browser tab that visits the web site. The latter is started with the initial request in a browser tab and keeps running while navigating within the web site, across the usage of links, forms, history, and <>. Eliom provides three language extensions to OCaml to provide an integrated development of client/server-programs, and to deal with the mentioned asymetricity between the client- and server-program: The partitioning of the program into client-, and server-sections, the direct usage of server-side toplevel values in client sections, and the declaration and handling of client values within the code for the server. It is advisable to read the section about <> first. For an outline of the implementation of those features, please refer to the chapter on <>. <> ==@@id="sections"@@ Sections (partitioning into client- and server-side) The source code of an Eliom module can be partitioned on its top-level into several //sections// to specify which code is to be compiled for and run in the server program, in the client program, or in both. A common OCaml module is comprised of a sequence of //structure items//, i.e. top level declarations of variables, types, modules etc. An Eliom module consists of a sequence of such structure items and client, server, and shared //sections//. The section declarations in turn may contain any number and kind of structure items. Code outside of those sections is compiled for the server side only. The sections (the latter contain code to be compiled and run on both sides) are introduced by the following syntax and may occur in any number or ordering: <> Declarations in the shared section are compiled separately for both the client //and// for the server program. They may refer only to declarations which are available on the client-side //and// on the server side. Note well, that they will refer possibly to different implementations: <> == Semantics Sections as-it act as a filter on the original source code during compilation: Only the structure items on the top-level, the server-section, and the shared-sections are compiled to the server program (or bytecode object files) by ##eliomc##. And only the structure items in client- and shared-sections are compiled to the client program (or bytecode object files) by ##js_of_eliom##. All top-level expressions are evaluated //early// while launching the program. In the server program they are thus evaluated while launching the server. //No request information is available at that time//. In the client program, top-level expressions are evaluated early in the initialization phase of the client process, particulary //before the DOM is in place//. This means, that you cannot do any DOM manipulation or access HTML-elements with <>. However, you can postpone that by <>. ==@@id="injections"@@ Injections (in the client-section) Eliom permits the direct usage of top-level server-side variables, and also of arbitrary expressions, in the client sections. Such a usage is called //injection//. It is also supported inside a [[href:#sharedinjection|shared section]]. Assuming you have a top-level variable ##v## defined on the server, its injection in the client section is introduced by prefixing it with a percent-sign ##%v##. It then holds the value of the server-side variable ##v## //at the time of the initial request of the client process//. <> It is also possible to inject an arbitrary server-side expression ##exp## in a client section. The injection is introduced by prefixing it with a percent-sign and parentheses, ##%(exp)##. Whenever an initial request of a client process is handled from the server, the expression ##exp## is evaluated. The injection then holds the resulting value in that specific client process. <> Note well that the value of an injection is //not updated// when the injected value on the server changes. However, you may inject reactive signals (cf. <>) to achieve the behavior of a client side values which updates alongside with a server correspondent. ===@@id="sharedinjection"@@ In a shared section Injections are also supported in the shared sections of an Eliom source file. When compiling the shared section to the client, the semantics is as described. However, when compiling an injection of a variable to the server program, it becomes just a new name of that variable. I.e. it will actually reflect changes made to the original variable. However, the same scoping rules hold for injections into the client- and shared-sections. <> ==@@id="clientvalues"@@ Client values (in the server-section) The notion //server-side client values// allows it to declare and deal with client values within the server-section (and is also supported in the [[wiki(15):doc#sharedclientvalues|shared section]]). A client-value may be declared in the server section as <> where ##exp## is an expression on the client side, which means it is compiled only for the client program, and may make use of any libraries available on the client, and where ##exp## has type ##typ## on the client side. The hole client value then has type ##typ Eliom_lib.client_value##. A value of type ##typ Eliom_lib.client_value## is //abstract on the server// (cf. <> (server)). But once it is sent to the client it becomes the value to which the expression ##exp## evaluated on the client side (cf. <> (client)). A client value expression is an arbitrary OCaml expression, but may additionaly contain //injections of server variables//, (cf. [[href:#injections|Injections into the client section]]). A variable ##v## in the scope of a client-value expression can be injected by prefixing it with a percent sign, ##%v##. A server-side expression ##exp## can be injected by ##%(exp)##. Note well, that the injection of a server side client-value ##v## of type ##typ Eliom_lib.client_value## results in a value ##%v## of type ##typ##. Thus, the value of the client value becomes concrete. The other way to make a client value concrete is to send it to the client, e.g. by using it in the HTML tree sent from the server in an Eliom application-service, or by sending it as-it in an Ocaml-service. For convenience, the indication of the type of a client value may be ommitted if it is derivible from its //usage// in the server code: < Eliom_lib.alert "ohyeah!" }} in Eliom.content.Html5.F.(div ~a:[a_onclick onclick] [pcdata "click me!"]) ... >> Here, the function ##a_onclick## has type ##(#Dom_html.mouseEvent Js.t -> unit) -> [> `OnClick ] Eliom_content_core.Html5.attrib##; this determines the type of the client value ##onclick## sufficiently. ===@@id="clientvaluesemantic"@@ Semantics The point in time of the evaluation of the expression of a client value (which also includes the occurrence of its side effects) depends on the context of the creation of the client value on the server. In Eliom, global client values are distinguished from request client values. Client values created while launching the server, i.e. while evaluating the top-level declarations of the server program, are termed //global client values//. The expressions of global client values are evaluated early in the initialization phase of the client process. Consider the following example to get an intuition of the order of evaluation of global client values; it will print the numbers 1 to 5 to the browser's console consecutively. <> Client values which are evaluated during the processing of a request are termed //request client values//. The expressions of request client values are evaluated after receiving the corresponding request on the client in the order of their occurrence on the server. In requests which change the content of the page withing the application (originating from a service of the <>), the expressions are evaluated //after the content has changed//. That way they may refer to the new DOM. If a client value is created outside of the initialization of the server program and also outside of the processing of a request, the exception {% <> %} is raised. ===@@id="sharedclientvalues"@@ In a shared section Client values are also supported in the shared-section of an Eliom program. They are then just directly compiled into the surrounding code. However, the same scoping rules apply to them: <> eliom-4.2/doc/manual-wiki/examples.wiki000066400000000000000000000001701255347715300201640ustar00rootroot00000000000000=@@id="examples"@@Demos= Go to the <> for several examples of code. eliom-4.2/doc/manual-wiki/illustrations/000077500000000000000000000000001255347715300203775ustar00rootroot00000000000000eliom-4.2/doc/manual-wiki/illustrations/Makefile000066400000000000000000000004131255347715300220350ustar00rootroot00000000000000 DENSITY=300 .PHONY: all clean all: compilation.png %.pdf: %.pgf pdflatex --jobname=$(basename $<) "\documentclass{standalone}\usepackage{my-pgf}\begin{document}\input{$<}\end{document}" %.png: %.pdf convert -density $(DENSITY) $< $@ clean: rm -rf *.aux *.log eliom-4.2/doc/manual-wiki/illustrations/compilation.pgf000066400000000000000000000022421255347715300234130ustar00rootroot00000000000000% $ pdflatex --jobname=compilation "\documentclass{standalone}\usepackage{my-pgf}\begin{document}\input{compilation.pgf}\end{document}" % $ convert -density 300 compilation.pdf compilation.png \begin{tikzpicture}[level distance=2cm,sibling distance=8cm] \begin{scope} [every node/.style={font=\ttfamily,node distance=4cm}, every path/.style={->}] \node (source) {program.eliom} child { node[file] (typemli) {\_server/program.type\_mli} { child[dashed] { node[file] (serverobj) {\_server/program.cmo} } child[dashed] { node[file] (clientobj) {\_client/program.cmo} { child[solid] { node[file] (clientprogram) {program.js} edge from parent node[command,auto] {js\_of\_eliom -o} }}}}}; \end{scope}n \begin{scope}[every path/.style={->}] \draw (source) to [bend right=20] node[command,auto,swap] (eliomc) {eliomc -c} (serverobj); \draw (source) to [bend left=20] node[command,auto] {js\_of\_eliom -c} (clientobj); \draw (source) to node[command,auto,swap] (inferpos) {} (typemli); \end{scope} \draw (inferpos |- eliomc) +(0.5em,0) node [command,anchor=east] {eliomc -infer}; \end{tikzpicture} eliom-4.2/doc/manual-wiki/illustrations/my-pgf.sty000066400000000000000000000003361255347715300223410ustar00rootroot00000000000000\usepackage{tikz} \usetikzlibrary{decorations,arrows,backgrounds,positioning,calc,shapes.multipart} \tikzset{every path/.style={>=stealth'}} \tikzstyle{file}=[ font=\ttfamily ] \tikzstyle{command}=[ font=\sffamily\small ] eliom-4.2/doc/manual-wiki/intro.wiki000066400000000000000000000147041255347715300175110ustar00rootroot00000000000000=Introduction= //This document is the Eliom manual, where you will find an explanation of all concepts provided by Eliom. If you are looking for a more didactic introduction, have a look at the <> which is a good starting point for beginners.// In the past few years, the web evolved from something quite static to a powerful platform, able to run very dynamic programs. Recent browsers make a very new kind of application possible, but most web developers still use the same old web frameworks that are not adapted to this evolution. We think these new possibilities deserve to rethink web programming techniques. The goal of Eliom (and other projects of the Ocsigen framework) is to propose a new way to write traditional web sites or sophisticated client/server web applications. It simplifies the development of complex applications by : * providing high level expressive concepts that fit very well the needs of web developers. This allows programming complex behaviour in very few lines of code. * helping the programmer to write safe and bug free applications. To improve security, it takes in charge itself many security issues. To reduce the number of bugs, it uses the very powerful typing system of the OCaml language to check many properties of the application at compile time: well formedness of HTML pages, types of page parameters, absence of broken links, etc. Eliom does not restrict the possibilities offered by the technology. In particular, the programmer can choose exactly the URL and parameter names he wants. Eliom also produces clean HTML code that can be parsed by search engines (even for client/server applications). Eliom is not a language but is using the OCaml language. This makes possible to use any existing library you want. Eliom web sites are written as OCaml modules (cma or cmxs), that will be loaded as a plugin into the Ocsigen server. ==Services== Pages are generated by //services//, which are some kind of functions that are called when you click on a link or send data through a form in a web page. Services can be associated to URLs. Eliom's //service identification mechanism// (that is: the way Eliom chooses the service to be executed) is actually much more sophisticated. It is using many different criteria, like the URL, but also special parameters, the HTTP method used (GET or POST), parameters names, the session, etc. Services usually return HTML pages, but you can also choose to return files, redirections, actions (that is: just perform a side effect on server side and redraw current page), applications, etc. There are even several ways to generate HTML. You can send it as raw text (as in most web programming frameworks). But we prefer to check at compile time that every page generated will respect the recommendation of the W3C. For this we are using the TyXML module. When defining a service, you must specify the names and types of the parameters it expects (in the URL or in the body of the HTTP request). Eliom will automatically check parameters and translate them to the right OCaml type (even for complex types like list or sets). The OCaml compiler checks that the parameters you put in links have the right type (w.r.t the service). It also checks that your forms correspond to the service to which they are associated. For example if your form contains a radio button, the service must expect a boolean value. Services can be created dynamically: for example you can create new services that depend on previous interaction with the user (form data for example). This is equivalent to what is usually called //continuation based web programming//. This makes possible for example to implement several step forms very easily (like booking a plane ticket). <> ==Sessions and server side state== Eliom also have a very sophisticated session mechanism. Sessions are a common pattern in web programming allowing some data (a state) to be stored on server side for each browser. This is used for example to recognize connected users, or to store a shopping basket. This is usually implemented by recording a session identifier in a browser cookie. With Eliom, session data are stored in //Eliom references//, which are some kind of reference whose value depends on the session (the session identifier sent in the cookie). But you can choose other //scope// than "session" for Eliom references: * it is also possible to define references with scope //"client process"// (which corresponds to a tab of your browser) (if you are using client side features). For example if you are implementing a game, you can have several instances of the game in several tabs. The score is stored on server side in an Eliom references with scope "client process". * Eliom also provide a scope //"session group"//. This allows grouping together for example all sessions belonging to the same user. Use this for example if you want to share the shopping basket between several devices (like my laptop and my smartphone...). * There is also a scope //"request"// to store data during the generation of a page. <> ==Client/server applications== Eliom applications are applications distributed between a server and a browser. An instance of the application is running in a tab of the browser and can communicate with the server. The full application is written in OCaml, as a single program, with a special syntax to distinguish between server side and client side code. Client side code is compiled to Javascript, using the Js~_of~_ocaml compiler, to be executed by the browser. It is possible to refer on client side to values defined in server side code. Communication between the server and the client is handled by Eliom automatically. The use of the same language on both sides makes it very easy to exchange data. It is possible to have a client side Eliom program and keep the traditional web interaction (with URLs, links, forms, bookmarks, and back button). When you click on a link, the client side program //does not stop!// Thus: * You can keep a state on client side during all the duration of the visit on the website. * You can set bookmarks corresponding to some states of the client side program. * Part of the page can persist after loading a new page. * If you are listening music or watching a video, it does not stop when you change page! <> eliom-4.2/doc/manual-wiki/menu.wiki000066400000000000000000000015521255347715300173170ustar00rootroot00000000000000= Eliom's Reference manual ==[[intro|Introduction]] ==Server side programming ===Services ====[[server-services|The different types of services]] ====[[server-params|Typing service parameters]] ====[[server-outputs|Writing service handlers]] ====[[server-links|Creating links and forms]] ===[[server-state|Sessions and server side state]] ===[[server-security|Security]] ==Client-server programming ===[[clientserver-applications|Eliom applications]] ===[[clientserver-language|Client-server syntax]] ===[[clientserver-html|Generating HTML5]] ===[[clientserver-communication|Communication]] ===[[clientserver-mobile|Mobile apps]] ===[[clientserver-wrapping|Custom wrapping]] ==Workflows ===[[workflow-distillery|Distillery]] ===[[workflow-compilation|Compilation]] ===[[workflow-configuration|Configuration & running]] ==[[examples|Examples]] ==[[misc|Miscellaneous]] eliom-4.2/doc/manual-wiki/misc.wiki000066400000000000000000000122021255347715300173000ustar00rootroot00000000000000=Miscellaneous= ==@@id="predefinedconstructs"@@HTML widgets ===Images, CSS, Javascript To include an image, simply use the function <>: <> The function <> creates the relative URL string from current URL (see above) to the URL of the image in the static directory configured in the configuration file. To simplify the creation of <>> tags for CSS or <>> tags for Javascript, use the following functions: <> <> ===@@id="basic_menu"@@Basic menus To make a menu on your web page, you can use the function <>. First, define your menu like this: <>) [ (infos, %:xmllist< More info ~>>); (tutorial, %:xmllist< Documentation ~>>) ] current >> Here, <>, <>, and <> are your three pages (generated for example by <>). Then <> will generate the following code: <
  • Home
  • More info
  • Documentation
  • >> Personalise it in your CSS style-sheet. <> takes a list of services without GET parameters. If you want one of the link to contains GET parameters, pre-apply the service. <> ===@@id="hier_menu"@@Hierarchical menus < a {color: blue;}\n .breadthmenu li {\n display: inline;\n padding: 0px 1em;\n margin: 0px;\n border-right: solid 1px black;}\n .breadthmenu li.eliomtools_last {border: none;}\n "]):: Html5_tools.F.structure_links mymenu ~service:s ()) ) (body [h1 [pcdata ("Page "^string_of_int i)]; h2 [pcdata "Depth first, whole tree:"]; div (Html5_tools.F.hierarchical_menu_depth_first ~whole_tree:true mymenu ~service:s ()); h2 [pcdata "Depth first, only current submenu:"]; div (Html5_tools.F.hierarchical_menu_depth_first mymenu ~service:s ()); h2 [pcdata "Breadth first:"]; div (Html5_tools.F.hierarchical_menu_breadth_first ~classe:["breadthmenu"] mymenu ~service:s ())])) let _ = register hier1 (f 1 hier1); register hier2 (f 2 hier2); register hier3 (f 3 hier3); register hier4 (f 4 hier4); register hier5 (f 5 hier5); register hier6 (f 6 hier6); register hier7 (f 7 hier7); register hier8 (f 8 hier8); register hier9 (f 9 hier9); register hier10 (f 10 hier10) >> ==Open ID== ==Atom== eliom-4.2/doc/manual-wiki/server-links.wiki000066400000000000000000000646421255347715300210100ustar00rootroot00000000000000 =Creating links and forms= <> >> ==@@id="links"@@Links To create a link ({{{}}}), use the <> function, as in these examples: < Lwt.return Html5.D.( html (head (title (pcdata "Links")) []) (body [p [a coucou [pcdata "coucou"] (); br (); a hello [pcdata "hello"] (); br (); a default [pcdata "default page of the dir"] (); br (); a uasuffix [pcdata "uasuffix"] (2007,06); br (); a coucou_params [pcdata "coucou_params"] (42,(22,"ciao")); br (); a raw_serv [pcdata "raw_serv"] [("sun","yellow");("sea","blue and pink")]; br (); a (Eliom_service.Http.external_service ~prefix:"http://fr.wikipedia.org" ~path:["wiki";""] ~get_params:(suffix (all_suffix "suff")) ()) [pcdata "OCaml on wikipedia"] ["OCaml"]; br (); Raw.a ~a:[a_href (Raw.uri_of_string "http://en.wikipedia.org/wiki/OCaml")] [pcdata "OCaml on wikipedia"] ]]))) >> See [[http://tests.ocsigen.org/rep/links]]. <> takes as first parameter the service you want to link to. The third parameter is the text of the link. The last parameter is for GET parameters you want to put in the link. The type of this parameter and the name of GET parameters depend on the service you link to. The links to Wikipedia shows how to define an external service (here it uses a suffix URL). For an external service without parameters, you can use the low level function <>, if you don't want to create an external service explicitly. Note that the path must be a list of strings: do not write {{{["foo/bar"]}}}, but {{{["foo";"bar"]}}}, otherwise, the "/" will be encoded in the URL.\\ If you want to create (mutually or not) recursive pages, create the service using <> or <> first, then register it in the table using (for example) <>: < Lwt.return (html (head (title (pcdata "")) []) (body [p [a linkrec [pcdata "click"] ()]]))) >> See[[http://tests.ocsigen.org./linkrec]]. (But you can also refer to //the current service// as <>.) ==@@id="forms"@@Forms ===Forms towards GET services The function <> allows creation of forms that use the GET method (parameters in the URL). It works like <> but takes a //function// that creates the form from the parameters names as parameter. < Html5.D.( [p [pcdata "Write an int: "; int_input ~input_type:`Text ~name:number_name (); pcdata "Write another int: "; int_input ~input_type:`Text ~name:number2_name (); pcdata "Write a string: "; string_input ~input_type:`Text ~name:string_name (); string_input ~input_type:`Submit ~value:"Click" ()]] )) let form = Eliom_registration.Html5.register_service ["form"] unit (fun () () -> let f = Html5.D.get_form coucou_params create_form in Lwt.return (html (head (title (pcdata "")) []) (body [f]))) >> See [[http://tests.ocsigen.org/form]] to see the function <> in action]].\\ >> If you want to use typed parameters, you cannot use functions like <> to create your forms (but you can use it if you want to use parameters defined with <>). Indeed, parameter names are typed to force them be used properly. In our example, <> has type <> and must be used with <> (or other widgets), whereas <> has type <> and must be used with <> (or other widgets). All functions for creating form widgets are detailed in <> (and <>). For untyped forms, you may use functions from <> or functions from the module <>. Here is a form linking to our (untyped) service <>. < Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [h1 [pcdata "Any Form"]; get_form raw_serv (fun () -> [p [pcdata "Form to raw_serv: "; raw_input ~input_type:`Text ~name:"plop" (); raw_input ~input_type:`Text ~name:"plip" (); raw_input ~input_type:`Text ~name:"plap" (); raw_input ~input_type:`Submit ~value:"Click" ()]]) ]))) >> Try this [[http://tests.ocsigen.org/anyform|form]]. >> ===POST parameters By default web page parameters are transferred in the URL (GET parameters). A web page may also expect POST parameters (that is, parameters that are not in the URL but in the body of the HTTP request, if the POST method is used). < Lwt.return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Version of the page without POST parameters"]]))) let my_service_with_post_params = Eliom_registration.Html5.register_post_service ~fallback:no_post_param_service ~post_params:Eliom_parameter.(string "value") (fun () value -> Lwt.return (html (head (title (pcdata "")) []) (body [h1 [pcdata value]]))) >> Services may take both GET and POST parameters: < Lwt.return (html (head (title (pcdata "")) []) (body [p [pcdata "No POST parameter, i:"; em [pcdata (string_of_int i)]]]))) let my_service_with_get_and_post = Eliom_registration.Html5.register_post_service ~fallback:get_no_post_param_service ~post_params:Eliom_parameter.(string "value") (fun i value -> Lwt.return (html (head (title (pcdata "")) []) (body [p [pcdata "Value: "; em [pcdata value]; pcdata ", i: "; em [pcdata (string_of_int i)]]]))) >> ===@@id="postforms"@@POST forms To create a POST form, use the <> function. It is similar to <> with an additional parameter for the GET parameters you want to put in the URL (if any). Here, <> is a page containing a form to the service <> (using Html5.F's functions) and <> (defined using the syntax extension) contains a form to <>, with a GET parameter. <> is a form to an external page. < let f = (Eliom_content.Html5.D.post_form my_service_with_post_params (fun chaine -> [p [pcdata "Write a string: "; string_input ~input_type:`Text ~name:chaine ()]]) ()) in Lwt.return (html (head (title (pcdata "form")) []) (body [f]))) let form3 = Eliom_registration.Html5.register_service ["form3"] Eliom_parameter.unit (fun () () -> let module Html5 = Html5.D in let f = (Eliom_content.Html5.D.post_form my_service_with_get_and_post (fun chaine -> <:html5list<

    Write a string: $string_input ~input_type:`Text ~name:chaine ()$

    ~>>) 222) in Lwt.return << $f$ ~>>) let form4 = Eliom_registration.Html5.register_service ["form4"] Eliom_parameter.unit (fun () () -> let module Html5 = Eliom_content.Html5.D in let f = (Eliom_content.Html5.D.post_form (external_post_service ~prefix:"http://www.petizomverts.com" ~path:["zebulon"] ~get_params:(int "i") ~post_params:(string "chaine") ()) (fun chaine -> <:html5list<

    Write a string: $string_input ~input_type:`Text ~name:chaine ()$

    ~>>) 222) in Lwt.return (html (head (title (pcdata "form")) []) (body [f]))) >> See the urls: [[http://tests.ocsigen.org/post|post without parameter]], [[http://tests.ocsigen.org/post2?i=123|post2 without POST parameter]], [[http://tests.ocsigen.org/form2|form2]], [[http://tests.ocsigen.org/form3|form3]], [[http://tests.ocsigen.org/form4|form4]]. ==@@id="advancedformsandparameters"@@Advanced forms and parameters This section shows more advanced use of page parameters and corresponding forms. ===Parsing parameters using regular expressions Eliom_parameter.regexp allows parsing page parameters using (Perl-compatible) regular expressions. We use the module <>, from //OCamlnet//. See the documentation about OCamlnet for more information. The following example shows a service that accepts only parameters values enclosed between <> and <>: < s) "myparam") (fun g () -> Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [p [pcdata g]]))) >> < s) "myparam") (fun g () -> Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [p [pcdata g]]))) >> [[http://tests.ocsigen.org/regexp?myparam=%5Btoto%5D| Try it]]. ===Boolean checkboxes Page may take parameter of type <>. A possible use of this type is in a form with //boolean checkboxes//, as in the example below: < let module Html5 = Html5.D in Lwt.return <<

    $pcdata (if case then "checked" else "not checked")$

    ~>>) let create_form_bool casename = let module Html5 = Html5.D in <:html5list<

    check? $bool_checkbox ~name:casename ()$
    $string_input ~input_type:`Submit ~value:"Click" ()$

    ~>> let form_bool = Eliom_registration.Html5.register_service ["formbool"] unit (fun () () -> let module Html5 = Html5.D in let f = get_form bool_params create_form_bool in Lwt.return << $f$ ~>>) >> [[http://tests.ocsigen.org/formbool| Try it]].\\ //Important warning:// As you can see, browsers do not send any value for unchecked boxes! An unchecked box is equivalent to no parameter at all! Thus it is not possible to distinguish between a service taking a boolean and a service taking no parameter at all (if they share the same URL). In Eliom services with higher priority are tried first, and then they are tried in order of registration. The first matching service will answer.\\ Other types similar to bool: * <> (page taking an optional parameter), * <> (either a parameter or another). See <>. ===Type <> Page may take several parameters of the same name. It is useful when you want to create a form with a variable number of fields. To do that with Eliom, use the type <>. For example <> means that the page will take zero, one or several parameters of name <>, all of type <>. The function you register will receive the parameters in a list. Example: < let module Html5 = Html5.D in let ll = List.map (fun s -> << $str:s$ ~>>) l in Lwt.return <<

    You sent: $list:ll$

    ~>>) >> These parameters may come from several kinds of widgets in forms. Here is an example of a form with several checkboxes, all sharing the same name, but with different values: < Lwt.return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Set Form"]; get_form set (fun n -> [p [pcdata "Form to set: "; string_checkbox ~name:n ~value:"box1" (); string_checkbox ~name:n ~value:"box2" ~checked:true (); string_checkbox ~name:n ~value:"box3" (); string_checkbox ~name:n ~value:"box4" (); string_input ~input_type:`Submit ~value:"Click" ()]]) ]))) >> [[http://tests.ocsigen.org/setform|Try it]].\\ Once again, note that there is no difference between an empty set or no parameter at all. If you register a service without parameters and a service with a set of parameters on the same URL, the service with higher priority, or the firstly registered service that matches, will answer. ===Select Here is an example of a select box. < Lwt.return (html (head (title (pcdata "")) []) (body [p [pcdata "You selected: "; strong [pcdata g]]]))) let create_select_form = (fun select_name -> Html5.D.( [p [pcdata "Select something: "; string_select ~name:select_name (Option ([] (* attributes *), "Bob" (* value *), None (* Content, if different from value *), false (* not selected *))) (* first line *) [Option ([], "Marc", None, false); (Optgroup ([], "Girls", ([], "Karin", None, false), [([a_disabled `Disabled], "Juliette", None, false); ([], "Alice", None, true); ([], "Germaine", Some (pcdata "Bob's mother"), false)]))] ; string_input ~input_type:`Submit ~value:"Send" ()]] )) let select_example = Eliom_registration.Html5.register_service ["select"] Eliom_parameter.unit (fun () () -> let open Html5.D in let f = get_form select_example_result create_select_form in Lwt.return (html (head (title (pcdata "")) []) (body [f]))) >> [[http://tests.ocsigen.org/select| Try it]].\\ To do "multiple" select boxes, use functions like <>. As you can see in the type, the service must be declared with parameters of type <>. ===Clickable images Here is an example of clickable image. You receive the coordinates the user clicked on. < let module Html5 = Html5.D in Lwt.return <<

    You clicked on coordinates: ($str:(string_of_int c.abscissa)$, $str:(string_of_int c.ordinate)$)

    ~>>) (* form to image *) let imageform = Eliom_registration.Html5.register_service ~path:["imageform"] ~get_params:Eliom_parameter.unit (fun () () -> Lwt.return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Image Form"]; get_form coord (fun n -> [p [image_input ~src:(make_uri ~service:(Eliom_service.static_dir ()) ["ocsigen5.png"]) ~name:n ()]]) ]))) >> [[http://tests.ocsigen.org/imageform| Try it]].\\ You may also send a value with the coordinates: < let module Html5 = Html5.D in Lwt.return <<

    You clicked on coordinates: ($str:(string_of_int c.abscissa)$, $str:(string_of_int c.ordinate)$)

    ~>>) (* form to image *) let imageform2 = Eliom_registration.Html5.register_service ~path:["imageform2"] ~get_params:Eliom_parameter.unit (fun () () -> Lwt.return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Image Form"]; get_form coord2 (fun n -> [p [int_image_input ~src:(make_uri ~service:(Eliom_service.static_dir ()) ["ocsigen5.png"]) ~name:n ~value:3 ()]]) ]))) >> [[http://tests.ocsigen.org/imageform2|Try it]]. ===Type <> Another way (than <>) to do variable length forms is to use indexed lists (using <>). The use of that feature is a bit more complex than <>. Here is an example of service taking an indexed list as parameter: < let module Html5 = Html5.D in let ll = List.map (fun s -> << $str:s$ ~>>) l in Lwt.return <<

    You sent: $list:ll$

    ~>>) >> Here is an example of link towards this service: [[http://tests.ocsigen.org/coucou?a.str%5B1%5D=titi&a.str%5B0%5D=toto|coucou?a.str[0]=toto&a.str[1]=titi]]. //Warning:// As for sets or bools, if a request has no parameter, it will be considered as the empty list. Services with higher priority are tried first, otherwise they are tried in order of registration. As you see, the names of each list element is built from the name of the list, the name of the list element, and an index. To spare you creating yourself these names, Eliom provides you an iterator to create them. < <:html5list<

    Write the value for $str:v$: $string_input ~input_type:`Text ~name:stringname ()$

    ~>>@init) ["one";"two";"three";"four"] <:html5list<

    $string_input ~input_type:`Submit ~value:"Click" ()$

    ~>> let listform = Eliom_registration.Html5.register_service ["listform"] Eliom_parameter.unit (fun () () -> let f = get_form coucou_list create_listform in let module Html5 = Eliom_content.Html5.D in Lwt.return << $f$ ~>>) >> [[http://tests.ocsigen.org/listform| Try it]].\\ //Important warning:// As we have seen in the section about boolean (or optional) parameters, it is not possible to distinguish between a boolean with value "false", and no parameter at all. This causes problems if you create a list of boolean or optional values, as it is not possible to know the length of the list. In that case, Eliom always takes the shortest possible list. ===Forms and suffixes Service with "suffix" URLs have an equivalent version with usual parameters, allowing creation of forms towards such services. Example: <Write the suffix: $int_input ~input_type:`Text ~name:suff ()$
    Write a string: $user_type_input (Ocsigen_lib.Url.string_of_url_path ~encode:false) ~input_type:`Text ~name:endsuff () $
    Write an int: $int_input ~input_type:`Text ~name:i ()$
    $string_input ~input_type:`Submit ~value:"Click" ()$

    ~>> let suffixform = Eliom_registration.Html5.register_service ["suffixform"] Eliom_parameter.unit (fun () () -> let f = get_form isuffix create_suffixform in let module Html5 = Eliom_content.Html5.D in Lwt.return << $f$ ~>>) >> [[http://tests.ocsigen.org/suffixform| Try it]]. ===Uploading files The <> parameter type allows files to be sent in your request. The service gets something of type <>. You can extract information using this using these functions (from <>): < string val get_filesize : Ocsigen_extensions.file_info -> int64 val get_original_filename : Ocsigen_extensions.file_info -> string >> <> returns the actual name of the uploaded file on the hard drive. <> gives the original filename. To make possible the upload of files, you must configure a directory for uploaded files in Ocsigen's configuration file. For example: <
    /tmp >> Files are kept in this directory only while processing the request. Then they are automatically cancelled. Thus your services must copy them somewhere else themselves if they want to keep them. In the following example, we create a new hard link to the file to keep it (the destination must be on the same partition of the disk). < let to_display = let newname = "/tmp/thefile" in (try Unix.unlink newname; with _ -> ()); Lwt_log.ign_debug (Eliom_request_info.get_tmp_filename file); Unix.link (Eliom_request_info.get_tmp_filename file) newname; let fd_in = open_in newname in try let line = input_line fd_in in close_in fd_in; line (*end*) with End_of_file -> close_in fd_in; "vide" in Lwt.return (html (head (title (pcdata "Upload")) []) (body [h1 [pcdata to_display]]))) let uploadform = Eliom_registration.Html5.register upload (fun () () -> let f = (post_form upload2 (fun file -> [p [file_input ~name:file (); br (); string_input ~input_type:`Submit ~value:"Send" () ]]) ()) in Lwt.return (html (head (title (pcdata "form")) []) (body [f]))) >> [[http://tests.ocsigen.org/upload| Try it]] (warning: uploading on ocsigen.org is forbidden). ===Raw POST data (advanced use) By specifying {{{~post_params:Eliom_parameter.raw_post_params}}}, it is possible to create a service that takes as parameter any POST data, as a stream. The only restriction is that it does not work if the content-type corresponds to URL encoded form data or multipart data (because in these cases, there are POST parameters, which are decoded by Eliom to find the service). See the API reference for more information. eliom-4.2/doc/manual-wiki/server-outputs.wiki000066400000000000000000000547511255347715300214130ustar00rootroot00000000000000 = Writing service handlers <> >> <> Once the <> identified the service responsible for a given URL it executes its service handler. The service handler is a function taking the GET and POST parameters as argument and returning the content to be sent to the client. The return type of the service handler depends on the function used to register it. On the most common case its HTML5 contents build with the TyXML library, but Eliom provides a lot of outputs modules to ease the implementation of common web interaction. See section <> for a comprehensive list. <> As Ocsigenserver, Eliom is based on cooperative threading library and service handler must be written in a cooperative way. See section <> for some examples. <> See section <>. ==@@id="predefined_outputs"@@ Predefined output modules === List of predefined output modules <> Services can send several types of data, using a variety of predefined modules. It is also possible to <>. The main predefined output modules are: <<| |@@class="empty"@@|=@@class="col2 c"@@Services|=@@colspan="2" class="col2 c"@@Coservices| |@@class="empty"@@|=@@class="col2 c"@@|=@@class="col2 c"@@attached\\named~ /~ anonymous|=@@class="col2 c"@@non-attached\\named~ /~ anonymous| |=Module|=description|=type|=options| >> <> ;<> : Registration of functions that generate html5 pages statically checked using polymorphic variant types. You may use constructor functions from <> or a syntax extension close to the standard html syntax. ;<> : Registration of functions that generate a portion of page using <> or the syntax extension (useful for <> requests for example). Do not use with Eliom applications: use <> instead. ;<> : Registration of functions that generate text html pages, without any typechecking of the content. The content type sent by the server is "text/html". ;<> : Registration of functions that generate CSS pages, without any typechecking of the content. The content type sent by the server is "{{{text/css}}}". ;<> : Registration of functions that generate text pages, without any typechecking of the content. The services return a pair of strings. The first one is the content of the page, the second one is the content type. ;<> : Registration of services that send files. See <> for an example of use. ;<> : Registration of services that send "byte" contents. It is used when big contents (that does not fit in memory) is generated. <> ;<> : Functor that generates a module that allows creation of services belonging to a client-server Eliom application (see <>). <> ;<> : Registration of actions (functions that do not generate any page, see <>). The page corresponding to the URL (without the coservice parameter that triggered the action) is reloaded after the action by default if possible. ;<> : Like <>, but the URL is not reloaded after the action. (Same as {{{Eliom_registration.Action}}} with {{{[`NoReload]}}} option). ;<> : Registration of HTTP redirections. The handler returns the service (without parameter) of the page you want to redirect to. The browser will get a 301 or 307 code in answer and redo the request to the new URL. To specify whether you want temporary (307) or permanent (301) redirections, use the <> parameter of registration functions. For example: <> or <>. ;<> : Same but the ouput type is a string. Use with care! Warning: According to the RFC of the HTTP protocol, the URL must be absolute! <> ;<> : Specialization of service registration functions by customizing the page type. <> ;<> : Registration of services sending marshalled OCaml values. See the section on <>. <> ;<> : Registration of services that can choose what they send, for example an HTML page or a file, depending on some situation (parameter, user logged or not, page present in a cache ...). It is also possible to create your own modules for other types of pages. See <> for an example of use. === Specific output modules <> ====@@id="eliomfiles"@@ Sending files === You may want to register a service that sends files. To do so, use the <> module. Example: < return "filename") >> Other example, with "suffix" services (see <>): < return ("//path//"^(Ocsigen_lib.Url.string_of_url_path ~encode:false s))) >> The extension <> is another way to handle static files. ====Sending portions of pages The <> modules allow you to register services that send portions of pages, of any "block" type for ##Html5.F##. It is sometimes useful to create AJAX pages (i.e. pages using the <> Javascript object). Note that the service returns a list of blocks. For sending HTML to client side Eliom application, <> is better suited. < Lwt.return [div [h2 [pcdata "Hallo"]; p [pcdata "Blablablabla"] ]]) >> The <> module allows the creation of new modules for registering portions of pages of other types. For example, <> is defined by: <> ====@@id="redirections"@@Redirections ===== Redirections to Eliom services The <> module allows you to register HTTP redirections.\\ If a request is made for such a service, the server asks the browser to retry with another URL. Such services return a GET service without parameter at all. Example: < Lwt.return coucou) >> If you want to give parameters to such services, use <> (see also in <>). Example: < Lwt.return (Eliom_service.preapply coucou_params (o,(22,"ee")))) >> The <> parameter may be either <> or <>. Note that the cost of a redirection is one more request and one more response. ===== Redirections to generated urls The <> allows you to register HTTP redirections to generated URLs. Usually, prefer <>, even for external redirections (using <>). Use <> only when it is not possible to have a service corresponding to an URL. Notice that the supplied URL must be absolute. ====@@id="actions"@@Actions Actions are used to perform side effects before generating the fallback of a service. When an action is called, the service handler is executed, then the service handler of the fallback service is executed. Eliom references of scope <> set in an action handler are still available in the service handler of the fallback. A common use of actions and non-attached coservices working together is the implementation of login/logout forms. An example is given in the chapter about the server-side state of the application (section sec-state-connect). In that example, actions and non-attached coservices make staightforward the implementation of the behaviour you generally want for such features: * Connection and disconnection stay on the same page, * If you want a connection/disconnection form on each page, no need to create a version with POST parameters of each service. The implementation of the same behaviour with usual Web programming techniques is usually much more complicated. ====@@id="any"@@ Registering services that decide what they want to send === You may want to register a service that will send, for instance, sometimes an HTML page, sometimes a file, sometimes something else. To do that, use the <> module, together with the <> function of the module you want to use. Example: < if s = "valid" then Eliom_registration.Html5.send (html (head (title (pcdata "")) []) (body [p [pcdata "This page has been statically typechecked. If you change the parameter in the URL you will get an unchecked text page"]])) else Eliom_registration.Html_text.send "

    It is not a valid page. Put type=\"valid\" in the URL to get a typechecked page.

    " ) >> ===== Dynamically modifying register options using Any You may also use <> to dynamically modify the parameters usually set on the register function. You can set the HTTP code, the charset, the content_type, the HTTP headers and the specific option of the output module. < Eliom_registration.Html5.send ~code:403 (html (head (title (pcdata "forbidden")) []) (body [p [pcdata "forbidden"]]))) >> ===== About kind type and how to serve application and other content with the same service In Eliom applications, changing the current page does not do always the same thing. When going to a page inside the same application by clicking a link (or calling <>) the client application perform a XmlHttpRequest and modify the displayed page according to the result. When going to content outside the application (an other site, a static file, etc.) the client leaves the application by changing the browser url. When using <>, there is no way to know before the request wether the content is from the same application or not. To that end there are phantom type annotations to the type of the {{{send}}} functions: <>. The <> takes a service handler that can server only one kind of content: that way it is not possible to inadvertantly mix kinds. The different kinds of content are: * Browser content: everything that can't be handled by application directly: ex Html pages, files * Block content: subparts of pages sent as XML: ex Flow5, Block. * Application content: pages of application. * Ocaml content: marshalled OCaml values. * Unknown content: content generated as text. Yet sometimes you may want to mix the kinds of contents a service can return. The function <> allows you to cast browser content to application content. When an application request some content cast through that function the server send some information telling the client to exit to that address instead. You should not use that on POST services: leaving the application sending POST parameters is not always possible and the request will be performed 2 times. For instance if you want to serve files if they exists and generate some error message with client side code otherwise, you should do something like that. < if Eliom_registration.File.check_file filename then Eliom_registration.appl_self_redirect Eliom_registration.File.send filename else My_application.send ~code:404 (html (head (title (pcdata "no page")) []) (body [p ~a:[a_onclick {{ do some client action }}] [pcdata "the file does not exist"]]))) >> Unknown content can be cast to browser content using <>. ===@@id="creating"@@Creating your own output modules=== ====@@id="customize"@@By customizing an existing registration module Using <> you can specialise a registration function to avoid code duplication. You can for instance for each service add parameters before calling the service handler, or modify the answer. A classical use is to check wether a user is logged in before serving the content of a page. That way, we don't need to do the check in every service handler and we can get directly the user informations. In this example, we check if we are in a session group telling that the user is connected. If it not the case, we generate a login page. When we are in a group, we retrieve the user informations and pass it to the service handler. It returns a title and the content of the body. That way, it also always generate the same css without code duplication. < Eliom_registration.Html5.page Lwt.t let translate page = match Eliom_state.get_volatile_data_session_group ~scope:Eliom_common.default_session_scope () with | None -> login_page () | Some group_name -> lwt user_info = get_user_info group_name in lwt (page_title,content) = page user_info in return (html (head (title (pcdata page_title)) [ Some css and things like that ]) (body content)) end module Connected = Eliom_registration.Customize ( Eliom_registration.Html5 ) ( Connected_param ) >> ==== By building the HTTP frame When you need to declare some kind of specific service, you may need to create your own registration module: For instance here we define a module serving integers as text. Notice that in that case you can and should use customize instead. For that you need to use the <> functor. < Some (Eliom_config.get_config_default_charset ()) | _ -> charset); res_content_type = (match content_type with | None -> r.Ocsigen_http_frame.res_content_type | _ -> content_type ); res_headers = (match headers with | None -> r.Ocsigen_http_frame.res_headers | Some headers -> Http_headers.with_defaults headers r.Ocsigen_http_frame.res_headers ); } end module Int = Eliom_mkreg.MakeRegister(Int_reg_base) >> If your {{{page}}} type has parameters you should use <> instead. ==@@id="lwt"@@ Writing cooperative service handlers with Lwt == Remember that a Web site written with Eliom is an OCaml application. This application must be able to handle several requests at the same time, in order to prevent a single request from making the whole server hang. To make this possible, Ocsigen uses //cooperative threads// (implemented in monadic style) which make them really easy to use (see <> module). Below is an example of a page written in a non-cooperative way, that has the effect of stopping the entire server for 5 seconds. No one will be able to query the server during this period: < Unix.sleep 5; Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [h1 [pcdata "Ok now, you can read the page."]]))) >> To solve this problem, use a cooperative version of {{{Unix.sleep}}}: <>: < lwt () = Lwt_unix.sleep 5.0 in Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [h1 [pcdata "Ok now, you can read the page."]]))) >> If you want to use, say, a database library that is not written in a cooperative way, but is thread-safe for preemptive threads, use the <> module to detach the computation. In the following example, we simulate the request by making a call to <>: < lwt () = Lwt_preemptive.detach Unix.sleep 5 in Lwt.return (html (head (title (pcdata "")) []) (body [h1 [pcdata "Ok now, you can read the page."]]))) >> ==@@id="error_handling"@@ Error handling == === Exception handling You can catch the exceptions raised during page generation in two places: * add an exception handler to services using the {{{?error_handler}}} parameter of the registration functions. * add a global exception handler using <> You can use it to catch exception <> and generate a custom 404 page. < match e with | Eliom_common.Eliom_404 -> Eliom_registration.Html5.send ~code:404 (html (head (title (pcdata "")) []) (body [h1 [pcdata "Eliom tutorial"]; p [pcdata "Page not found"]])) | Eliom_common.Eliom_Wrong_parameter -> Eliom_registration.Html5.send (html (head (title (pcdata "")) []) (body [h1 [pcdata "Eliom tutorial"]; p [pcdata "Wrong parameters"]])) | e -> fail e) >> ===@@id="infofallbacks"@@ Fallback services You can check wether a service was directly called or if it was used as a fallback using the <> function. In case of coservices registered with a restricted scope, you can check which state was closed using <> === Error in service handlers of actions If something wrong happens during an action, it is possible to inform the service generating the page. For instance, if you want to display a "wrong password" message after an aborted connection. To transmit that kind of information, use Eliom references (see module <>) created using scope <>, the value will be available to the service generating the page. Other examples: creating user accounts using actions. If the creation fails you may want to display some message to the user, like "password too weak" or "name already used". eliom-4.2/doc/manual-wiki/server-params.wiki000066400000000000000000000253561255347715300211520ustar00rootroot00000000000000= Service parameters = <> >> ==@@id="parameters"@@ Parameters == === Services with parameters === Service handlers take two parameters. The first one is for GET parameters (that is, parameters in the URL) and the second one for POST parameters (parameters in the body of the HTTP request). The parameters labeled <> or <> of the services creation functions indicate the type of the parameters. The specification of parameters types is done using combinators defined in module <>. For example <> means that the page does not take any parameter, and <> means that the page takes a parameter called {{{foo}}}, of type {{{int}}}. Here is an example of a service with GET parameters: <> <> Eliom will automaticaly try to convert the parameters and call the handler with the right OCaml types (here {{{int * (int * string)}}}). It is possible to register several services on the same path, if they do not have the same parameters. Eliom will try them in order of registration until one of them is able to answer (and send an error otherwise). In the example above, if {{{i}}} is not an integer, the server will display an error-message (try to change the value in the URL).\\ //Warning:// The infix function {{{( ** )}}} is to be used only to construct pairs (not tuples).\\ ===@@id="suffix"@@Path suffixes as parameters The following example shows how to create a service with "suffix" service (taking the end of the URL as a parameter, as wikis do very often) and how to get server information: < Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [p [pcdata "The suffix of the url is "; strong [pcdata ((string_of_int year)^"/" ^(string_of_int month))]; pcdata ", your user-agent is "; strong [pcdata (Eliom_request_info.get_user_agent ())]; pcdata ", your IP is "; strong [pcdata (Eliom_request_info.get_remote_ip ())]]]))) >> This service will answer to URLs like {{{http://.../uasuffix/2000/11}}}, see [[http://tests.ocsigen.org/uasuffix/2007/7]]. Suffix parameters have names, because we can create forms towards these services. {{{uasuffix/2000/11}}} is equivalent to {{{uasuffix/?year=2000&month=11}}}.\\ > allows both a suffix and other parameters.\\ > allows the end of the suffix to be taken as a {{{string list}}}.\\ < return Eliom_content.Html5.D.( html (head (title (pcdata "")) []) (body [p [pcdata "The suffix of the url is "; strong [pcdata (string_of_int suff)]; pcdata " followed by "; strong [pcdata (Ocsigen_lib.Url.string_of_url_path ~encode:false endsuff)]; pcdata " and i is equal to "; strong [pcdata (string_of_int i_param)]]])))28 >> See [[http://tests.ocsigen.org/isuffix/11/a/b/c?i=22]]. If you want parameters in the path but not always at the end, use the <> parameter specification. It will match for example URLs like {{{/param1/const/param2}}}. Example: < Lwt.return Html5.D.(html (head (title (pcdata "")) []) (body [ h1 [pcdata "Suffix with constants"]; p [pcdata ("Parameters are "^s1^" and "^s2)]]))) >> See [[http://tests.ocsigen.org/constfix/aa/toto/bb]]. ===Custom parameter types The following example shows how to use your own types : < A | "B" -> B | _ -> raise (Failure "mysum_of_string") let string_of_mysum = function | A -> "A" | B -> "B" let mytype = Eliom_registration.Html5.register_service ~path:["mytype"] ~get_params: (Eliom_parameter.user_type mysum_of_string string_of_mysum "valeur") (fun x () -> let v = string_of_mysum x in Lwt.return (html (head (title (pcdata "")) []) (body [p [pcdata (v^" is valid. Now try with another value.")]]))) >> See [[http://tests.ocsigen.org/mytype?valeur=A]]. See also <> in the chapter about client-server communication, which shows how to use a <> from the client-side. ===@@id="any"@@Untyped parameters If you want a service that answers to requests with any parameters, use the <> value. The service will get an association list of strings. Example: < let module Html5 = Eliom_content.Html5.D in let ll = List.map (fun (a,s) -> << ($str:a$, $str:s$) ~>>) l in Lwt.return <<

    You sent: $list:ll$

    ~>>) >> See [[http://tests.ocsigen.org/any?sun=yellow&sea=blue]]. It is possible to use {{{Eliom_parameter.any}}} with other parameters combinators. But {{{any}}} must be the last one. For example: {{{(int "i" ** any)}}}. ==@@id="nonlocalizedparameters"@@Non localized parameters== Non localized parameters are GET or POST parameters that are not taken into account by Eliom for choosing the service. They have a special prefix (added automatically by Eliom). Use this if you want some information to be available or not, through parameters, for all of your services. < Lwt.return (html (head (title (pcdata "")) []) (body [p [pcdata "i = "; strong [pcdata (string_of_int i)]]; (match Eliom_parameter.get_non_localized_get_parameters my_nl_params with | None -> p [pcdata "I do not have my non localized parameters"] | Some (a, s) -> p [pcdata "I have my non localized parameters, "; pcdata ("with values a = "^string_of_int a^ " and s = "^s^".")] )])) ) >> To create a link or a form with non-localized parameters, use the optional parameter <> of functions <>, <> or <>. Example: < Lwt.return Html5.D.( html (head (title (pcdata "")) []) (body [p [a ~service:nlparams [pcdata "without nl params"] 4]; p [a ~service:nlparams ~nl_params:(Eliom_parameter.add_nl_parameter Eliom_parameter.empty_nl_params_set my_nl_params (22, "oh") ) [pcdata "with nl params"] 5]; get_form ~service:nlparams ~nl_params:(Eliom_parameter.add_nl_parameter Eliom_parameter.empty_nl_params_set my_nl_params (22, "oh") ) (fun iname -> [p [pcdata "form with hidden nl params"; int_input ~input_type:`Text ~name:iname (); string_input ~input_type:`Submit ~value:"Send" ()]]); get_form ~service:nlparams (fun iname -> let (aname, sname) = Eliom_parameter.get_nl_params_names my_nl_params in [p [pcdata "form with nl params fiels"; int_input ~input_type:`Text ~name:iname (); int_input ~input_type:`Text ~name:aname (); string_input ~input_type:`Text ~name:sname (); string_input ~input_type:`Submit ~value:"Send" ()]]); ])) ) >> It is also possible to create a new service by adding the non localized parameters to an existing service: <> Then create your link as usual, for example [[http://tests.ocsigen.org/nlparams?i=22&__nl_n_tutoeliom-mynlparams.s=aa&__nl_n_tutoeliom-mynlparams.a=11]]. eliom-4.2/doc/manual-wiki/server-security.wiki000066400000000000000000000166611255347715300215350ustar00rootroot00000000000000==How to write secure applications with Eliom== Eliom and Ocsigen server are taking in charge a lot of security issues automatically. This unburdens the programmer from having to think about most of security problems. This page details various possible designs flaws of web applications, how Eliom and Ocsigen server (possibly) protects you against a possible exploitation of these flaws, and where you should be careful. //Please help us maintaining this page, by sending us any comments.// <<|For more details on the various flaws, see e.g. [[http://www.amazon.fr/Web-Application-Hackers-Handbook-Discovering/dp/0470170778/|this book]].>> === HTTPS If your Web site is using HTTP, all requests and responses may be intercepted. If you want your Web site to be secure, never send private data through http: * Pages containing personal data must be sent only through HTTPS * Passwords must be sent to the server only through HTTPS * Use secure Eliom references to record user name or user id once the user is connected, otherwise the session ID may be send through HTTP. === The application only does client-side verification This is probably the biggest (and most dangerous) possible mistake. As the user has an entire control over the data sent to the server, **never** assume that the data sent by the client has been verified (even if there some checking function in Javascript or O'Browser). Instead, reimplement all verifications server side. * As a (small) mitigating factor, Eliom automatically checks that the type of the parameters is correct. * Suggested approach: use permissions to control if the user is allowed to perform an action. Then, ** when creating a form, check if the user has the required permission (if not, you will usually display a message //insufficient permissions// instead of the form) ** in the service that answers to the form, perform the exact same check However, as we are using sage unmarshaling, incorrect data will never crash the server. Example: Never trust the (current) user id sent by the client process. Always take the userid from the session, through cookies. === Incorrect access controls This typically happens if authentication is badly implemented, or altogether missing in some places. * each URL should implement user verification. Never assume that the user comes from a trusted url, for example because the url is secret. * use a programmatic, layered model, which encodes the various user rights (for ex: admin/moderators/editors/connected users/anonymous). Thus a compromised login will not compromise the entire application * Do not leak information through erroneous login (such as //this login does not exist//). Always answer //Bad login or password//, using always the same string * Do not permit too many near-simultaneous login attempts, either for the same login, or from the same IP. You can use the module Lwt_throttle to delay login, if too many connections are started. === [[http://en.wikipedia.org/wiki/Code_injection|Code injection]] * Eliom modules are written in OCaml, which is a compiled language. This prevents all code injection possible with script languages. * No sql injection is possible if you use Macaque or PGOCaml, which use PostgreSQL prepared statements. * No Html injection is possible, as unsafe HTML characters are always escaped before being written. === [[http://en.wikipedia.org/wiki/Directory_traversal|Path traversal]] * The module <> can be used to prevent access to files or entire directories, from both Staticmod and Eliom. * Even if <> is activated, users can only expose their own files; see the {{{localpath}}} option for details. * Occurrences of the {{{'..'}}} pattern appearing in Urls are automatically removed by the server * Ocsigen automatically decode HTML entities in URLs, which protects against attacks based on quoted characters === [[http://en.wikipedia.org/wiki/Session_fixation|Session fixation]] * Ocsigen cookies are cryptographically generated, and cannot be guessed by the attacker. Thus the attacker cannot control, or supply, the cookie of the client. * To be completely safe, do not issue tokens to anonymous users, or issue a new token as soon as a login/logout takes place <<|Vincent : le dernier truc est mal expliqué et je ne comprends pas trop ce qu'il a voulu dire. Il faut expliquer pourquoi les cookies de Eliom sont sûrs de ce point de vue, et dire comment éviter un pb avec des cookies que l'on pose soi-même. token = ?>> === [[http://en.wikipedia.org/wiki/Cross-site_scripting|Cross-site scripting (XSS)]] * most XSS attacks require code injection, from which you are automatically protected (see above) * However, avoid at all costs to put user-supplied text in sensitive tags, including: ** {{{

    Ocsigen mobile

    Hello World !
    eliom-4.2/pkg/distillery/mobile/static!js!PROJECT_NAME.js000066400000000000000000000000001255347715300230150ustar00rootroot00000000000000eliom-4.2/pkg/etc/000077500000000000000000000000001255347715300140345ustar00rootroot00000000000000eliom-4.2/pkg/etc/mime.types000066400000000000000000000352541255347715300160620ustar00rootroot00000000000000# This is a comment. I love comments. # This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at . # MIME type Extensions application/activemessage application/andrew-inset ez application/applefile application/atom+xml atom application/atomicmail application/batch-smtp application/beep+xml application/cals-1840 application/cnrp+xml application/commonground application/cpl+xml application/cybercash application/dca-rft application/dec-dx application/dvcs application/edi-consent application/edifact application/edi-x12 application/eshop application/font-tdpfr application/http application/hyperstudio application/iges application/index application/index.cmd application/index.obj application/index.response application/index.vnd application/iotp application/ipp application/isup application/mac-binhex40 hqx application/mac-compactpro cpt application/macwriteii application/marc application/mathematica application/mathml+xml mathml application/msword doc application/news-message-id application/news-transmission application/ocsp-request application/ocsp-response application/octet-stream bin dms lha lzh exe class so dll dmg application/oda oda application/ogg ogg application/parityfec application/pdf pdf application/pgp-encrypted application/pgp-keys application/pgp-signature application/pkcs10 application/pkcs7-mime application/pkcs7-signature application/pkix-cert application/pkix-crl application/pkixcmp application/postscript ai eps ps application/prs.alvestrand.titrax-sheet application/prs.cww application/prs.nprend application/prs.plucker application/qsig application/rdf+xml rdf application/reginfo+xml application/remote-printing application/riscos application/rtf application/sdp application/set-payment application/set-payment-initiation application/set-registration application/set-registration-initiation application/sgml application/sgml-open-catalog application/sieve application/slate application/smil smi smil application/srgs gram application/srgs+xml grxml application/timestamp-query application/timestamp-reply application/tve-trigger application/vemmi application/vnd.3gpp.pic-bw-large application/vnd.3gpp.pic-bw-small application/vnd.3gpp.pic-bw-var application/vnd.3gpp.sms application/vnd.3m.post-it-notes application/vnd.accpac.simply.aso application/vnd.accpac.simply.imp application/vnd.acucobol application/vnd.acucorp application/vnd.adobe.xfdf application/vnd.aether.imp application/vnd.amiga.ami application/vnd.anser-web-certificate-issue-initiation application/vnd.anser-web-funds-transfer-initiation application/vnd.audiograph application/vnd.blueice.multipass application/vnd.bmi application/vnd.businessobjects application/vnd.canon-cpdl application/vnd.canon-lips application/vnd.cinderella application/vnd.claymore application/vnd.commerce-battelle application/vnd.commonspace application/vnd.contact.cmsg application/vnd.cosmocaller application/vnd.criticaltools.wbs+xml application/vnd.ctc-posml application/vnd.cups-postscript application/vnd.cups-raster application/vnd.cups-raw application/vnd.curl application/vnd.cybank application/vnd.data-vision.rdz application/vnd.dna application/vnd.dpgraph application/vnd.dreamfactory application/vnd.dxr application/vnd.ecdis-update application/vnd.ecowin.chart application/vnd.ecowin.filerequest application/vnd.ecowin.fileupdate application/vnd.ecowin.series application/vnd.ecowin.seriesrequest application/vnd.ecowin.seriesupdate application/vnd.enliven application/vnd.epson.esf application/vnd.epson.msf application/vnd.epson.quickanime application/vnd.epson.salt application/vnd.epson.ssf application/vnd.ericsson.quickcall application/vnd.eudora.data application/vnd.fdf application/vnd.ffsns application/vnd.fints application/vnd.flographit application/vnd.framemaker application/vnd.fsc.weblaunch application/vnd.fujitsu.oasys application/vnd.fujitsu.oasys2 application/vnd.fujitsu.oasys3 application/vnd.fujitsu.oasysgp application/vnd.fujitsu.oasysprs application/vnd.fujixerox.ddd application/vnd.fujixerox.docuworks application/vnd.fujixerox.docuworks.binder application/vnd.fut-misnet application/vnd.grafeq application/vnd.groove-account application/vnd.groove-help application/vnd.groove-identity-message application/vnd.groove-injector application/vnd.groove-tool-message application/vnd.groove-tool-template application/vnd.groove-vcard application/vnd.hbci application/vnd.hhe.lesson-player application/vnd.hp-hpgl application/vnd.hp-hpid application/vnd.hp-hps application/vnd.hp-pcl application/vnd.hp-pclxl application/vnd.httphone application/vnd.hzn-3d-crossword application/vnd.ibm.afplinedata application/vnd.ibm.electronic-media application/vnd.ibm.minipay application/vnd.ibm.modcap application/vnd.ibm.rights-management application/vnd.ibm.secure-container application/vnd.informix-visionary application/vnd.intercon.formnet application/vnd.intertrust.digibox application/vnd.intertrust.nncp application/vnd.intu.qbo application/vnd.intu.qfx application/vnd.irepository.package+xml application/vnd.is-xpr application/vnd.japannet-directory-service application/vnd.japannet-jpnstore-wakeup application/vnd.japannet-payment-wakeup application/vnd.japannet-registration application/vnd.japannet-registration-wakeup application/vnd.japannet-setstore-wakeup application/vnd.japannet-verification application/vnd.japannet-verification-wakeup application/vnd.jisp application/vnd.kde.karbon application/vnd.kde.kchart application/vnd.kde.kformula application/vnd.kde.kivio application/vnd.kde.kontour application/vnd.kde.kpresenter application/vnd.kde.kspread application/vnd.kde.kword application/vnd.kenameaapp application/vnd.koan application/vnd.liberty-request+xml application/vnd.llamagraphics.life-balance.desktop application/vnd.llamagraphics.life-balance.exchange+xml application/vnd.lotus-1-2-3 application/vnd.lotus-approach application/vnd.lotus-freelance application/vnd.lotus-notes application/vnd.lotus-organizer application/vnd.lotus-screencam application/vnd.lotus-wordpro application/vnd.mcd application/vnd.mediastation.cdkey application/vnd.meridian-slingshot application/vnd.micrografx.flo application/vnd.micrografx.igx application/vnd.mif mif application/vnd.minisoft-hp3000-save application/vnd.mitsubishi.misty-guard.trustweb application/vnd.mobius.daf application/vnd.mobius.dis application/vnd.mobius.mbk application/vnd.mobius.mqy application/vnd.mobius.msl application/vnd.mobius.plc application/vnd.mobius.txf application/vnd.mophun.application application/vnd.mophun.certificate application/vnd.motorola.flexsuite application/vnd.motorola.flexsuite.adsi application/vnd.motorola.flexsuite.fis application/vnd.motorola.flexsuite.gotap application/vnd.motorola.flexsuite.kmr application/vnd.motorola.flexsuite.ttc application/vnd.motorola.flexsuite.wem application/vnd.mozilla.xul+xml xul application/vnd.ms-artgalry application/vnd.ms-asf application/vnd.ms-excel xls application/vnd.ms-lrm application/vnd.ms-powerpoint ppt application/vnd.ms-project application/vnd.ms-tnef application/vnd.ms-works application/vnd.ms-wpl application/vnd.mseq application/vnd.msign application/vnd.music-niff application/vnd.musician application/vnd.netfpx application/vnd.noblenet-directory application/vnd.noblenet-sealer application/vnd.noblenet-web application/vnd.novadigm.edm application/vnd.novadigm.edx application/vnd.novadigm.ext application/vnd.obn application/vnd.osa.netdeploy application/vnd.palm application/vnd.pg.format application/vnd.pg.osasli application/vnd.powerbuilder6 application/vnd.powerbuilder6-s application/vnd.powerbuilder7 application/vnd.powerbuilder7-s application/vnd.powerbuilder75 application/vnd.powerbuilder75-s application/vnd.previewsystems.box application/vnd.publishare-delta-tree application/vnd.pvi.ptid1 application/vnd.pwg-multiplexed application/vnd.pwg-xhtml-print+xml application/vnd.quark.quarkxpress application/vnd.rapid application/vnd.s3sms application/vnd.sealed.net application/vnd.seemail application/vnd.shana.informed.formdata application/vnd.shana.informed.formtemplate application/vnd.shana.informed.interchange application/vnd.shana.informed.package application/vnd.smaf application/vnd.sss-cod application/vnd.sss-dtf application/vnd.sss-ntf application/vnd.street-stream application/vnd.svd application/vnd.swiftview-ics application/vnd.triscape.mxs application/vnd.trueapp application/vnd.truedoc application/vnd.ufdl application/vnd.uplanet.alert application/vnd.uplanet.alert-wbxml application/vnd.uplanet.bearer-choice application/vnd.uplanet.bearer-choice-wbxml application/vnd.uplanet.cacheop application/vnd.uplanet.cacheop-wbxml application/vnd.uplanet.channel application/vnd.uplanet.channel-wbxml application/vnd.uplanet.list application/vnd.uplanet.list-wbxml application/vnd.uplanet.listcmd application/vnd.uplanet.listcmd-wbxml application/vnd.uplanet.signal application/vnd.vcx application/vnd.vectorworks application/vnd.vidsoft.vidconference application/vnd.visio application/vnd.visionary application/vnd.vividence.scriptfile application/vnd.vsf application/vnd.wap.sic application/vnd.wap.slc application/vnd.wap.wbxml wbxml application/vnd.wap.wmlc wmlc application/vnd.wap.wmlscriptc wmlsc application/vnd.webturbo application/vnd.wrq-hp3000-labelled application/vnd.wt.stf application/vnd.wv.csp+wbxml application/vnd.xara application/vnd.xfdl application/vnd.yamaha.hv-dic application/vnd.yamaha.hv-script application/vnd.yamaha.hv-voice application/vnd.yellowriver-custom-menu application/voicexml+xml vxml application/watcherinfo+xml application/whoispp-query application/whoispp-response application/wita application/wordperfect5.1 application/x-bcpio bcpio application/x-cdlink vcd application/x-chess-pgn pgn application/x-compress application/x-cpio cpio application/x-csh csh application/x-director dcr dir dxr application/x-dvi dvi application/x-futuresplash spl application/x-gtar gtar application/x-gzip application/x-hdf hdf application/x-javascript js application/x-koan skp skd skt skm application/x-latex latex application/x-netcdf nc cdf application/x-sh sh application/x-shar shar application/x-shockwave-flash swf application/x-stuffit sit application/x-sv4cpio sv4cpio application/x-sv4crc sv4crc application/x-tar tar application/x-tcl tcl application/x-tex tex application/x-texinfo texinfo texi application/x-troff t tr roff application/x-troff-man man application/x-troff-me me application/x-troff-ms ms application/x-ustar ustar application/x-wais-source src application/x400-bp application/xhtml+xml xhtml xht application/xslt+xml xslt application/xml xml xsl application/xml-dtd dtd application/xml-external-parsed-entity application/zip zip audio/32kadpcm audio/amr audio/amr-wb audio/basic au snd audio/cn audio/dat12 audio/dsr-es201108 audio/dvi4 audio/evrc audio/evrc0 audio/g722 audio/g.722.1 audio/g723 audio/g726-16 audio/g726-24 audio/g726-32 audio/g726-40 audio/g728 audio/g729 audio/g729D audio/g729E audio/gsm audio/gsm-efr audio/l8 audio/l16 audio/l20 audio/l24 audio/lpc audio/midi mid midi kar audio/mpa audio/mpa-robust audio/mp4a-latm audio/mpeg mpga mp2 mp3 audio/parityfec audio/pcma audio/pcmu audio/prs.sid audio/qcelp audio/red audio/smv audio/smv0 audio/telephone-event audio/tone audio/vdvi audio/vnd.3gpp.iufp audio/vnd.cisco.nse audio/vnd.cns.anp1 audio/vnd.cns.inf1 audio/vnd.digital-winds audio/vnd.everad.plj audio/vnd.lucent.voice audio/vnd.nortel.vbk audio/vnd.nuera.ecelp4800 audio/vnd.nuera.ecelp7470 audio/vnd.nuera.ecelp9600 audio/vnd.octel.sbc audio/vnd.qcelp audio/vnd.rhetorex.32kadpcm audio/vnd.vmx.cvsd audio/x-aiff aif aiff aifc audio/x-alaw-basic audio/x-mpegurl m3u audio/x-pn-realaudio ram ra audio/x-pn-realaudio-plugin application/vnd.rn-realmedia rm audio/x-wav wav chemical/x-pdb pdb chemical/x-xyz xyz image/bmp bmp image/cgm cgm image/g3fax image/gif gif image/ief ief image/jpeg jpeg jpg jpe image/naplps image/png png image/prs.btif image/prs.pti image/svg+xml svg image/t38 image/tiff tiff tif image/tiff-fx image/vnd.cns.inf2 image/vnd.djvu djvu djv image/vnd.dwg image/vnd.dxf image/vnd.fastbidsheet image/vnd.fpx image/vnd.fst image/vnd.fujixerox.edmics-mmr image/vnd.fujixerox.edmics-rlc image/vnd.globalgraphics.pgb image/vnd.mix image/vnd.ms-modi image/vnd.net-fpx image/vnd.svf image/vnd.wap.wbmp wbmp image/vnd.xiff image/x-cmu-raster ras image/x-icon ico image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-rgb rgb image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd message/delivery-status message/disposition-notification message/external-body message/http message/news message/partial message/rfc822 message/s-http message/sip message/sipfrag model/iges igs iges model/mesh msh mesh silo model/vnd.dwf model/vnd.flatland.3dml model/vnd.gdl model/vnd.gs-gdl model/vnd.gtw model/vnd.mts model/vnd.parasolid.transmit.binary model/vnd.parasolid.transmit.text model/vnd.vtu model/vrml wrl vrml multipart/alternative multipart/appledouble multipart/byteranges multipart/digest multipart/encrypted multipart/form-data multipart/header-set multipart/mixed multipart/parallel multipart/related multipart/report multipart/signed multipart/voice-message text/calendar ics ifb text/css css text/directory text/enriched text/html html htm text/parityfec text/plain asc txt text/prs.lines.tag text/rfc822-headers text/richtext rtx text/rtf rtf text/sgml sgml sgm text/t140 text/tab-separated-values tsv text/uri-list text/vnd.abc text/vnd.curl text/vnd.dmclientscript text/vnd.fly text/vnd.fmi.flexstor text/vnd.in3d.3dml text/vnd.in3d.spot text/vnd.iptc.nitf text/vnd.iptc.newsml text/vnd.latex-z text/vnd.motorola.reflex text/vnd.ms-mediapackage text/vnd.net2phone.commcenter.command text/vnd.sun.j2me.app-descriptor text/vnd.wap.si text/vnd.wap.sl text/vnd.wap.wml wml text/vnd.wap.wmlscript wmls text/x-setext etx text/xml text/xml-external-parsed-entity video/bmpeg video/bt656 video/celb video/dv video/h261 video/h263 video/h263-1998 video/h263-2000 video/jpeg video/mp1s video/mp2p video/mp2t video/mp4v-es video/mpv video/mpeg mpeg mpg mpe video/nv video/parityfec video/pointer video/quicktime qt mov video/smpte292m video/vnd.fvt video/vnd.motorola.video video/vnd.motorola.videop video/vnd.mpegurl mxu m4u video/vnd.nokia.interleaved-multimedia video/vnd.objectvideo video/vnd.vivo video/x-msvideo avi video/x-sgi-movie movie x-conference/x-cooltalk ice eliom-4.2/pkg/filelist.ml000066400000000000000000000073421255347715300154340ustar00rootroot00000000000000type descr = { interface : string list; internal : string list; } let server = { interface = [ "eliom_bus"; "eliom_comet"; "eliom_common"; "eliom_config"; "eliom_content"; "eliom_cookie"; "eliom_extension"; "eliom_lib"; "eliom_mkforms"; "eliom_mkreg"; "eliom_parameter"; "eliom_pervasives"; "eliom_react"; "eliom_reference"; "eliom_registration"; "eliom_request_info"; "eliom_service"; "eliom_state"; "eliom_tools"; "eliom_tools_common"; "eliom_types"; "eliom_uri"; "eliom_wrap"; ]; internal = [ "eliom_comet_base"; "eliom_common_base"; "eliom_content_"; "eliom_content_core"; "eliom_cookies_base"; "eliom_error_pages"; "eliom_lazy"; "eliom_lib_base"; "eliom_parameter_base"; "eliom_pervasives_base"; "eliom_process"; "eliom_registration_base"; "eliom_service_base"; "eliom_types_base"; "eliommod"; "eliommod_cli"; "eliommod_cookies"; "eliommod_datasess"; "eliommod_gc"; "eliommod_naservices"; "eliommod_pagegen"; "eliommod_parameters"; "eliommod_persess"; "eliommod_sersess"; "eliommod_services"; "eliommod_sessadmin"; "eliommod_sessexpl"; "eliommod_sessiongroups"; "eliommod_timeouts"; ] } let client = { interface = [ "eliom_bus"; "eliom_client"; "eliom_comet"; "eliom_config"; "eliom_content"; "eliom_content_core"; "eliom_lazy"; "eliom_lib"; "eliom_mkforms"; "eliom_parameter"; "eliom_pervasives"; "eliom_react"; "eliom_registration"; "eliom_service"; "eliom_tools"; "eliom_types"; "eliom_unwrap"; "eliom_uri"; ]; internal = [ "eliom_comet_base"; "eliom_common"; "eliom_common_base"; "eliom_content_"; "eliom_cookies_base"; "eliom_lib_base"; "eliom_parameter_base"; "eliom_pervasives_base"; "eliom_process"; "eliom_registration_base"; "eliom_request"; "eliom_request_info"; "eliom_service_base"; "eliom_types_base"; "eliommod_cookies"; "eliommod_dom"; "eliommod_jstable"; "eliommod_parameters"; ]; } let server_ext = { interface = [ "atom_feed"; "eliom_atom"; "eliom_openid"; "eliom_s2s"]; internal = [] } let ocamlbuild = { interface = [ "ocamlbuild_eliom" ]; internal = [] } let (-.-) name ext = name ^ "." ^ ext let exts el sl = List.flatten ( List.map (fun ext -> List.map (fun name -> name -.- ext) sl) el) let list_to_file filename list = let oc = open_out filename in List.iter (fun s -> output_string oc s; output_char oc '\n'; ) list; close_out oc;; let client_mllib = client.interface @ client.internal let client_extra = exts ["cmi"] client.interface let client_api = let names = client.interface in names let server_mllib = server.interface @ server.internal let server_extra = exts ["cmi"] server.interface @ exts ["cmx"] (server.interface @ server.internal) let server_api = let names = server.interface @ List.map (fun e -> "extensions/" ^ e) server_ext.interface in names let server_ext_mllib = server_ext.interface @ server_ext.internal let server_ext_extra = exts ["cmi"] server_ext.interface @ exts ["cmx"] (server_ext.interface @ server_ext.internal) let ocamlbuild_mllib = ocamlbuild.interface @ ocamlbuild.internal let ocamlbuild_extra = exts ["cmi"] ocamlbuild.interface @ exts ["cmx"] (ocamlbuild.interface @ ocamlbuild.internal) let ocamlbuild_api = ocamlbuild.interface let templates_dir = "pkg/distillery" let templates = Array.to_list (Sys.readdir templates_dir) let templates_files = List.map (fun name -> name, Array.to_list (Sys.readdir (templates_dir^"/"^name))) templates eliom-4.2/pkg/man/000077500000000000000000000000001255347715300140345ustar00rootroot00000000000000eliom-4.2/pkg/man/eliom-distillery.1000066400000000000000000000024011255347715300174020ustar00rootroot00000000000000.TH eliom-distillery 1 2012-12-17 .SH NAME eliom-distillery \- Scaffolding for your Eliom-projects. .SH SYNOPSIS .B eliom-distillery .BI \-dir .B eliom-distillery .BI \-name \ name [ .BI \-template \