
# Creating links and forms


## Links

To create a link (`<a>`), use the [`Eliom_content.Html.D.a`](./eliom.server/Eliom_content-Html-D.md#val-a) function, as in these examples:

```ocaml
 open Eliom_content

 let links = Eliom_registration.Html.create
   ~path:(Eliom_service.Path ["rep";"links"])
   ~meth:(Eliom_service.Get Eliom_parameter.unit)
 (fun () () ->
   Lwt.return
    Html.D.(
      html
       (head (title (txt "Links")) [])
       (body
         [p
          [a ~service:theservice [txt "coucou"] (); br ();
           a ~service:hello [txt "hello"] (); br ();
           a ~service:default
             [txt "default page of the dir"] (); br ();
           a ~service:uasuffix
             [txt "uasuffix"] (2007,06); br ();
           a ~service:service_with_params
             [txt "Service with params"] (42,(22,"ciao")); br ();
           a ~service:raw_serv
             [txt "raw_serv"] [("sun","yellow");("sea","blue and pink")]; br ();
           a
             ~service:(Eliom_service.extern
                ~prefix:"http://fr.wikipedia.org"
                ~path:["wiki";""]
                ~meth:(Eliom_service.Get
                         Eliom_parameter.(suffix (all_suffix "suff")))
                ())
             [txt "OCaml on wikipedia"]
             ["OCaml"]; br ();
           Raw.a
             ~a:[a_href (Raw.uri_of_string "http://en.wikipedia.org/wiki/OCaml")]
             [txt "OCaml on wikipedia"]
         ]])))
```
[`Eliom_content.Html.D.a`](./eliom.server/Eliom_content-Html-D.md#val-a) takes as first parameter the service you want to link to. The second 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 link 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 [`Eliom_content.Html.D.Raw.a`](./eliom.server/Eliom_content-Html-D-Raw.md#val-a), 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.<br/>

If you want to create (mutually or not) recursive pages, create the service using [`Eliom_service.create`](./eliom.server/Eliom_service.md#val-create) first, then register it in the table using (for example) [`Eliom_registration.Html.register`](./eliom.server/Eliom_registration-Html.md#val-register):

```ocaml
let linkrec =
  Eliom_service.create
    ~path:(Eliom_service.Path ["linkrec"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit) ()

let _ =
  Eliom_registration.Html.register
    linkrec
    (fun () () ->
       Lwt.return
         (html
            (head (title (txt "")) [])
            (body [p [a ~service:linkrec [txt "click"] ()]])))
```
(You can also refer to *the current service* via `reload_action` ([`Eliom_service_sigs.S.reload_action`](./eliom.server/Eliom_service_sigs-module-type-S.md#val-reload_action)).


## Forms


### Raw forms

Modules [`Eliom_content.Html.F`](./eliom.server/Eliom_content-Html-F.md) and [`Eliom_content.Html.D`](./eliom.server/Eliom_content-Html-D.md) define form elements with the usual typed interface from TyXML. Use this for example if you have a client side program and want to manipulate the form contents from client side functions (for example do a server function call with the form elements content).

Example: <!--wodoc:@ class=shared-->

```ocaml
let%shared mk_form ()
  =
  let open Eliom_content.Html in
  let open Eliom_content.Html.F in
  let theinput = D.input () in
  let thesubmit =
    D.input ~a:[a_input_type `Submit; a_value "Go"] ()
  in
  Raw.form
    ~a:
      [ a_onsubmit
          [%client
            fun ev ->
              let value = Js.to_string ~%theinput##.value in
              ...
          ]
      ]
    [theinput; thesubmit]
```

### Typed forms towards GET services

In contrast, modules `Eliom_content.Html.D.Form` and `Eliom_content.Html.F.Form` provide functions for creating typed forms towards Eliom services. Use them if you want to create regular HTML forms, (with submit button).

Our examples use shorthands to these modules, e.g., simply `Form`, assuming an appropriate context. See [`Eliom_content_sigs.LINKS_AND_FORMS.Form`](./eliom.server/Eliom_content_sigs-module-type-LINKS_AND_FORMS-Form.md) for the `Form` API documentation.

The function `Eliom_content.Html.D.Form.get_form` allows creation of forms that use the GET method (parameters in the URL). It works like [`Eliom_content.Html.D.a`](./eliom.server/Eliom_content-Html-D.md#val-a) but takes a *function* that creates the form from the parameters names as parameter.

```ocaml
let create_form =
  (fun (number_name, (number2_name, string_name)) ->
    Html.D.(
      [p [txt "Write an int: ";
        Form.input ~input_type:`Text ~name:number_name Form.int;
        txt "Write another int: ";
        Form.input ~input_type:`Text ~name:number2_name Form.int;
        txt "Write a string: ";
        Form.input ~input_type:`Text ~name:string_name Form.string;
        Form.input ~input_type:`Submit ~value:"Click" Form.string]]
    ))

let form =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["form"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
       let f = Html.D.Form.get_form ~service:service_with_params create_form in
       Lwt.return
         (html
           (head (title (txt "")) [])
           (body [f])))
```
Parameter names are typed to make sure that they are used properly. The form-creating functions in <!--wodoc:span class="code"-->Eliom\_content.Html.D.Form<!--wodoc:end--> (respectively <!--wodoc:span class="code"-->Eliom\_content.Html.F.Form<!--wodoc:end-->) accept an argument of type `Eliom_content.Html.D.Form.param` (respectively `Eliom_content.Html.F.Form.param`), which needs to match the type of the parameter used. For example, <!--wodoc:span class="code"-->number\_name<!--wodoc:end--> has type <!--wodoc:span class="code"-->int param\_name<!--wodoc:end-->, so <!--wodoc:span class="code"-->Form.int<!--wodoc:end--> must be used with <!--wodoc:span class="code"-->Form.input<!--wodoc:end--> (or with the other widgets), whereas <!--wodoc:span class="code"-->string\_name<!--wodoc:end--> has type <!--wodoc:span class="code"-->string param\_name<!--wodoc:end--> and must be used in conjunction with the argument <!--wodoc:span class="code"-->Form.string<!--wodoc:end-->. Creating form widgets are described in detail in `Eliom_content.Html.D.Form` (and `Eliom_content.Html.F.Form`).

For untyped forms, you may use functions from the module [`Eliom_content.Html.D.Raw`](./eliom.server/Eliom_content-Html-D-Raw.md). Here is a form linking to our (untyped) service `raw_serv`.

```ocaml
let raw_form =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["anyform"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
      Lwt.return
        Html.D.(html
                   (head (title (txt "")) [])
                   (body
                      [h1 [txt "Any Form"];
                       Form.get_form ~service:raw_serv
                         (fun () ->
                           [p [txt "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" ()]])
                        ])))
```

### 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).

```ocaml
let no_post_param_service =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["post"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
      Lwt.return
        (html
         (head (title (txt "")) [])
         (body [h1 [txt
                      "Version of the page without POST parameters"]])))

let my_service_with_post_params =
  Eliom_registration.Html.create_attached_post
    ~fallback:no_post_param_service
    ~post_params:Eliom_parameter.(string "value")
    (fun () value ->
      Lwt.return
        (html
         (head (title (txt "")) [])
         (body [h1 [txt value]])))
```
Services may take both GET and POST parameters:

```ocaml
let get_no_post_param_service =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["post2"])
    ~meth:(Eliom_service.Get (Eliom_parameter.int "i"))
    (fun i () ->
      Lwt.return
        (html
         (head (title (txt "")) [])
         (body [p [txt "No POST parameter, i:";
                   em [txt (string_of_int i)]]])))

let my_service_with_get_and_post =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["post2"])
    ~meth:(Eliom_service.Post (Eliom_parameter.int "i",
                               Eliom_parameter.string "value"))
    (fun i value ->
      Lwt.return
        (html
           (head (title (txt "")) [])
           (body [p [txt "Value: ";
                     em [txt value];
                     txt ", i: ";
                     em [txt (string_of_int i)]]])))
```

### POST forms

To create a POST form, use the `Eliom_content.Html.D.Form.post_form` function. It is similar to `Eliom_content.Html.D.Form.get_form` with an additional parameter for the GET parameters you want to put in the URL (if any). Here, <!--wodoc:span class="code"-->form2<!--wodoc:end--> is a page containing a form to the service <!--wodoc:span class="code"-->post<!--wodoc:end--> (using Html.F's functions) and <!--wodoc:span class="code"-->form3<!--wodoc:end--> (defined using the syntax contains a form to <!--wodoc:span class="code"-->post2<!--wodoc:end-->, with a GET parameter. <!--wodoc:span class="code"-->form4<!--wodoc:end--> is a form to an external page.

*Warning:* Some examples in this section use the Tyxml syntax extension. (See `Tyxml's manual`). *Warning:* After installing Tyxml, `tyxml-ppx` should be added to the lists of SERVER PACKAGES and CLIENT PACKAGES in the Makefile.options file of your project.

```ocaml
  let form2 =
    Eliom_registration.Html.create
      ~path:(Eliom_service.Path ["form2"])
      ~meth:(Eliom_service.Get Eliom_parameter.unit)
      (fun () () ->
         let f =
           (Eliom_content.Html.D.Form.post_form ~service:my_service_with_post_params
              (fun chaine ->
                 [p [txt "Write a string: ";
                  Form.input
                    ~input_type:`Text ~name:chaine
                    Form.string]]) ())
         in
         Lwt.return
           (html
             (head (title (txt "form")) [])
             (body [f])))

let form3 =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["form3"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
       let module Html = Html.D in
       let f  =
         (Eliom_content.Html.D.Form.post_form ~service:my_service_with_get_and_post
            (fun chaine ->
              [ [%html "<p> Write a string:
                      "[Form.input
                          ~input_type:`Text ~name:chaine
                          Form.string)" </p>"])
            222) in
       Lwt.return
         [%html "<html>
              <head><title>Example</title></head>
              <body>"[f]"</body></html>"])

let form4 =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["form4"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
  (fun () () ->
     let module Html = Eliom_content.Html.D in
     let f  =
       (Eliom_content.Html.D.Form.post_form
          ~service:(Eliom_service.extern
             ~prefix:"http://www.petizomverts.com"
             ~path:["zebulon"]
             ~meth:(Eliom_service.Post (int "i", string "chaine"))
             ())
          (fun chaine ->
            [ [%html "<p> Write a string:
                     "[Form.input ~input_type:`Text ~name:chaine
                         Form.string]" </p> "])
          222) in
     Lwt.return
       (html
        (head (title (txt "form")) [])
        (body [f])))
```

## 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 <!--wodoc:span class="code"-->Netstring\_pcre<!--wodoc:end-->, from *OCamlnet*. See the documentation about OCamlnet for more information. The following example shows a service that accepts only parameters values enclosed between <!--wodoc:span class="code"-->`{%html:<!--wodoc:end-->%} and {%html:<!--wodoc:span class="code"-->%}`<!--wodoc:end-->:

```ocaml
let r = Netstring_pcre.regexp "\\\\[(.*)\\\\]"

let regexp =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["regexp"])
    ~meth:
      (Eliom_service.Get
        Eliom_parameter.(regexp r "$1" (fun s -> s) "myparam"))
    (fun g () ->
      Lwt.return
        Html.D.(html
                  (head (title (txt "")) [])
                  (body [p [txt g]])))

```
```ocaml
let myregexp = Netstring_pcre.regexp "\\[(.*)\\]"

let regexpserv =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["regexp"])
    ~meth:(Eliom_service.Get
            Eliom_parameter.(regexp myregexp "$1" (fun s -> s) "myparam"))
    (fun g () ->
      Lwt.return
        Html.D.(html
                  (head (title (txt "")) [])
                  (body [p [txt g]])))
```

### Boolean checkboxes

Page may take parameter of type <!--wodoc:span class="code"-->bool<!--wodoc:end-->. A possible use of this type is in a form with *boolean checkboxes*, as in the example below:

```ocaml
(* Form with bool checkbox: *)
let bool_params =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["bool"])
    ~meth:(Eliom_service.Get Eliom_parameter.(bool "case"))
  (fun case () ->
    let module Html = Html.D in
    Lwt.return
      [%html "<html>
           <head><title>Example</title></head>
           <body>
           <p>
             "[txt (if case then "checked" else "not checked")]"
           </p>
           </body>
         </html> "])

let create_form_bool casename =
    let module Html = Html.D in
    [ [%html "<p>check? "[Form.bool_checkbox_one ~name:casename ()]" <br/>
        "[Form.input ~input_type:`Submit ~value:"Click" Form.string]"</p> "] ]

let form_bool =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["formbool"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
  (fun () () ->
     let module Html = Html.D in
     let f = Form.get_form ~service:bool_params create_form_bool in
     Lwt.return
       [%html "<html>
            <head><title>Example</title></head>
            <body> "[f]" </body>
          </html> "])


```
*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.<br/>

Other types similar to bool:

- `Eliom_parameter.opt` (page taking an optional parameter),
- `Eliom_parameter.sum` (either a parameter or another).
See [`Eliom_parameter_sigs.S`](./eliom.server/Eliom_parameter_sigs-module-type-S.md).


### Type <!--wodoc:span class="code"-->set<!--wodoc:end-->

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 `Eliom_parameter.set`. For example, <!--wodoc:span class="code"-->set int "val"<!--wodoc:end--> means that the page will take zero, one, or several parameters of name <!--wodoc:span class="code"-->"val"<!--wodoc:end-->, all of type <!--wodoc:span class="code"-->int<!--wodoc:end-->. The function you register will receive the parameters in a list. Example:

```ocaml
let set = Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["set"])
    ~meth:(Eliom_service.Get Eliom_parameter.(set string "s"))
  (fun l () ->
    let module Html = Html.D in
    let ll =
      List.map
        (fun s -> [%html "<strong>"[txt s]"</strong>"]) l
    in
    Lwt.return
    [%html "<html>
         <head><title>Example</title></head>
         <body>
         <p>
           You sent:
           "ll"
         </p>
         </body>
       </html> "])
```
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:

```ocaml
(* form to set *)
let setform = Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["setform"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
      Lwt.return
        (html
           (head (title (txt "")) [])
           (body [h1 [txt "Set Form"];
                  Form.get_form ~service:set
                    (fun n ->
                      [p [txt "Form to set: ";
                          Form.checkbox
                            ~name:n ~value:"box1"
                            Form.string;
                          Form.checkbox
                            ~name:n ~value:"box2" ~checked:true
                            Form.string;
                          Form.checkbox
                            ~name:n ~value:"box3"
                            Form.string;
                          Form.checkbox
                            ~name:n ~value:"box4"
                            Form.string;
                          Form.input
                            ~input_type:`Submit ~value:"Click"
                            Form.string]])
                ])))
```
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.

```ocaml
let select_example_result = Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["select"])
    ~meth:(Eliom_service.Get Eliom_parameter.(string "s"))
    (fun g () ->
      Lwt.return
        (html
           (head (title (txt "")) [])
           (body [p [txt "You selected: ";
                     strong [txt g]]])))

let create_select_form =
  (fun select_name ->
    Html.D.(
      [p [txt "Select something: ";
        Form.select Form.string ~name:select_name
          (Form.Option ([] (* attributes *),
                        "Bob" (* value *),
                        None (* Content, if different from value *),
                        false (* not selected *))) (* first line *)
          [Form.Option ([], "Marc", None, false);
          (Form.Optgroup
          ([],
           "Girls",
           ([], "Karin", None, false),
           [([a_disabled ()], "Juliette", None, false);
            ([], "Alice", None, true);
            ([], "Germaine", Some (txt "Bob's mother"), false)]))]
          ;
        Form.input ~input_type:`Submit ~value:"Send" Form.string]]
    ))

let select_example =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["select"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
  (fun () () ->
     let open Html.D in
     let f = Form.get_form ~service:select_example_result create_select_form in
     Lwt.return
       (html
         (head (title (txt "")) [])
         (body [f])))
```
To do "multiple" select boxes, use functions like `Eliom_content.Html.D.Form.multiple_select`. As you can see in the type, the service must be declared with parameters of type `Eliom_parameter.set`.


### Clickable images

Here is an example of clickable image. You receive the coordinates the user clicked on.

```ocaml
  let coord = Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["coord"])
    ~meth:(Eliom_service.Get Eliom_parameter.(coordinates "coord"))
  (fun c () ->
    let module Html = Html.D in
    Lwt.return
      [%html" <html>
           <head><title>Example</title></head>
           <body>
           <p>
             You clicked on coordinates:
             ("[txt (string_of_int c.abscissa)]", "[txt (string_of_int c.ordinate)]")
           </p>
           </body>
         </html> "])

(* form to image *)
let imageform = Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["imageform"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
      Lwt.return
        (html
           (head (title (txt "")) [])
           (body [h1 [txt "Image Form"];
                  Form.get_form ~service:coord
                    (fun n ->
                      [p [Form.image_input
                            ~src:(make_uri ~service:(Eliom_service.static_dir ()) ["ocsigen5.png"])
                            ~name:n
                            ()]])
                ])))
```

### Type <!--wodoc:span class="code"-->list<!--wodoc:end-->

Another way (than `Eliom_parameter.set`) to do variable length forms is to use indexed lists (using `Eliom_parameter.list`). The use of that feature is a bit more complex than <!--wodoc:span class="code"-->set<!--wodoc:end-->. Here is an example of service taking an indexed list as parameter:

```ocaml
(* lists *)
let service_list =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["thepath"])
    ~meth:(Eliom_service.Get Eliom_parameter.(list "a" (string "str")))
    (fun l () ->
      let open Eliom_content.Html.D in
      let ll = List.map (fun s -> strong [txt s]) l in
      Lwt.return (html (head (title (txt "Example")) []) (body [p ll])))
```
*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.

```ocaml
(* Form with list: *)
let create_listform f =
  (* Here, f.it is an iterator like List.map,
     but it must be applied to a function taking 3 arguments
     (unlike 1 in map), the first one being the name of the parameter,
     and the second one the element of list.
     The last parameter of f.it is the code that must be appended at the
     end of the list created
  *)
  let open Eliom_content.Html.D in
  f.Eliom_parameter.it
    (fun stringname v init ->
      p
        [ txt "Write the value for "
        ; txt v
        ; txt " :"
        ; Form.input ~input_type:`Text ~name:stringname Form.string ]
      :: init)
    ["one"; "two"; "three"; "four"]
    [p [Form.input ~input_type:`Submit ~value:"Click" Form.string]]

let _ =
  Eliom_registration.Html.create
    ~path:(Eliom_service.Path ["listform"])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
      let open Eliom_content.Html.D in
      let f = Form.get_form ~service:service_list create_listform in
      Lwt.return (html (head (title (txt "Example")) []) (body [f])))
```
*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:

```ocaml
(* Form for service with suffix: *)
let create_suffixform ((suff, endsuff),i) =
     let module Html = Eliom_content.Html.D in
    [%html "<p>Write the suffix:
      "[Form.input ~input_type:`Text ~name:suff Form.int]" <br/>
      Write a string: "[Form.input
         ~input_type:`Text ~name:endsuff Form.string]
         " <br/>
      Write an int: "[Form.input ~input_type:`Text ~name:i Form.int]" <br/>
      "[Form.input ~input_type:`Submit ~value:"Click" Form.string]"</p> "]

let suffixform = Eliom_registration.Html.create
  ~path:(Eliom_service.Path ["suffixform"])
  ~meth:(Eliom_service.Get Eliom_parameter.unit)
  (fun () () ->
     let f = Form.get_form ~service:isuffix create_suffixform in
     let module Html = Eliom_content.Html.D in
     Lwt.return
      [%html "<html>
           <head><title>Example</title></head>
           <body> "[f]" </body>
         </html> "])

```
Decode the URL encoded string using `Ocsigen_lib.Url.string_of_url_path ~encode:false`


### Uploading files

The `Eliom_parameter.file` parameter type allows files to be sent in your request. The service gets something of type `Ocsigen_extensions.file_info`. You can extract information using this using these functions (from [`Eliom_request_info`](./eliom.server/Eliom_request_info.md)):

```ocaml
val get_tmp_filename : Ocsigen_extensions.file_info -> string
val get_filesize : Ocsigen_extensions.file_info -> int64
val get_original_filename : Ocsigen_extensions.file_info -> string

```
[`Eliom_request_info.get_tmp_filename`](./eliom.server/Eliom_request_info.md#val-get_tmp_filename) returns the actual name of the uploaded file on the hard drive. [`Eliom_request_info.get_original_filename`](./eliom.server/Eliom_request_info.md#val-get_original_filename) gives the original filename.

To enable file upload, you must configure a directory for uploaded files in Ocsigen's configuration file. For example: <!--wodoc:div class="pre"--> \<uploaddir\>/tmp\</uploaddir\> <!--wodoc:end-->

Files are kept in this directory only while processing the request. They are automatically removed afterwards. Therefore, your services must copy the files somewhere else, if the files are to be kept. 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.)

```ocaml
let upload = Eliom_service.create
    ~path:(Eliom_service.Path ["upload"])
    ~meth:(Eliom_service.Get unit)
    ()

let upload2 = Eliom_registration.Html.create
   ~path:(Eliom_service.Path ["upload"])
   ~meth:(Eliom_service.Post (Eliom_parameter.unit,
                              Eliom_parameter.file "file"))
    (fun () file ->
      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 (txt "Upload")) [])
           (body [h1 [txt to_display]])))


let uploadform = Eliom_registration.Html.register upload
    (fun () () ->
      let f =
        (Form.post_form ~service:upload2
           (fun file ->
             [p [Form.file_input ~name:file ();
                 br ();
                 Form.input ~input_type:`Submit ~value:"Send" Form.string
               ]]) ()) in
      Lwt.return
        (html
           (head (title (txt "form")) [])
           (body [f])))


```

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