package eliom

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file eliommod_datasess.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
(* Ocsigen
 * http://www.ocsigen.org
 * Module eliommod_datasess.ml
 * Copyright (C) 2007 Vincent Balat
 *
 * This program 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, with linking exception;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *)
(*****************************************************************************)
(*****************************************************************************)
(** Internal functions used by Eliom:                                        *)

(** Volatile data tables                                                     *)

(*****************************************************************************)
(*****************************************************************************)

open Eliom_lib

let compute_cookie_info sitedata secure_o secure_ci cookie_info =
  let secure = Eliom_common.get_secure ~secure_o ~sitedata () in
  if secure
  then
    let _, c, _ = secure_ci in
    c, true
  else cookie_info, false

(* to be called during a request *)
let close_data_state ~scope ~secure_o ?sp () =
  let sp = Eliom_common.sp_of_option sp in
  try
    let cookie_level = Eliom_common.cookie_level_of_user_scope scope in
    let (_, cookie_info, _), secure_ci =
      Eliom_common.get_cookie_info sp cookie_level
    in
    let sitedata = Eliom_request_info.get_sitedata_sp ~sp in
    let cookie_info, secure =
      compute_cookie_info sitedata secure_o secure_ci cookie_info
    in
    let full_st_name = Eliom_common.make_full_state_name ~sp ~secure ~scope in
    let _, ior =
      Lazy.force
        (Eliom_common.Full_state_name_table.find full_st_name !cookie_info)
    in
    match !ior with
    | Eliom_common.SC c ->
        (* There is only one way to close a session:
           remove it from the session group table.
           It will remove all the data table entries
           and also the entry in the session table *)
        (match scope with
        | `Session_group _ -> (
          (* If we want to close all the group of browser sessions,
                   the node is found in the group table: *)
          match
            Eliommod_sessiongroups.Data.find_node_in_group_of_groups
              !(c.Eliom_common.dc_session_group)
          with
          | None ->
              Lwt_log.ign_error ~section:Lwt_log.eliom
                "No group of groups. Please report this problem."
          | Some g -> Eliommod_sessiongroups.Data.remove g)
        | `Session _ | `Client_process _ ->
            (* If we want to close a (tab/browser) session, the node is found
                 in the cookie info: *)
            Eliommod_sessiongroups.Data.remove
              c.Eliom_common.dc_session_group_node);
        ior := Eliom_common.SCNo_data
    | _ -> ()
  with Not_found -> ()

let fullsessgrp ~cookie_level ~sp set_session_group =
  Eliommod_sessiongroups.make_full_group_name ~cookie_level
    sp.Eliom_common.sp_request.Ocsigen_extensions.request_info
    (Eliom_common.get_site_dir_string sp.Eliom_common.sp_sitedata)
    (Eliom_common.get_mask4 sp.Eliom_common.sp_sitedata)
    (Eliom_common.get_mask6 sp.Eliom_common.sp_sitedata)
    set_session_group

let rec find_or_create_data_cookie ?set_session_group
    ~(cookie_scope : Eliom_common.cookie_scope) ~secure_o ?sp ()
  =
  (* If the cookie does not exist, create it.
     Returns the cookie info for the cookie *)
  let cookie_level = Eliom_common.cookie_level_of_user_scope cookie_scope in
  let sp = Eliom_common.sp_of_option sp in
  let new_data_cookie sitedata full_st_name table =
    let set_session_group =
      match cookie_scope with
      | `Client_process n ->
          (* We create a group whose name is the
                   browser session cookie
                   and put the tab session into it. *)
          let v =
            find_or_create_data_cookie ~cookie_scope:(`Session n) ~secure_o ~sp
              ()
          in
          Some Eliom_common.(Hashed_cookies.to_string v.dc_hvalue)
      | _ -> set_session_group
    in
    let fullsessgrp = fullsessgrp ~cookie_level ~sp set_session_group in
    let c = Eliommod_cookies.make_new_session_id () in
    let hc = Eliom_common.Hashed_cookies.hash c in
    let hc_string = Eliom_common.Hashed_cookies.to_string hc in
    let usertimeout = ref Eliom_common.TGlobal (* See global table *) in
    let serverexp =
      ref None
      (* Some 0. *)
      (* None = never. We'll change it later. *)
    in
    let fullsessgrpref = ref fullsessgrp in
    let node = Eliommod_sessiongroups.Data.add sitedata hc_string fullsessgrp in
    Eliom_common.SessionCookies.replace
      (* actually it will add the cookie *)
      table hc_string
      { Eliom_common.Data_cookie.full_state_name = full_st_name
      ; expiry = serverexp
      ; timeout = usertimeout
      ; session_group = fullsessgrpref
      ; session_group_node = node };
    { Eliom_common.dc_hvalue = hc
    ; Eliom_common.dc_set_value = Some c
    ; Eliom_common.dc_timeout = usertimeout
    ; Eliom_common.dc_exp = serverexp
    ; Eliom_common.dc_cookie_exp =
        ref (Eliom_common.default_client_cookie_exp ())
    ; Eliom_common.dc_session_group = fullsessgrpref
    ; Eliom_common.dc_session_group_node = node }
  in
  let (_, cookie_info, _), secure_ci =
    Eliom_common.get_cookie_info sp cookie_level
  in
  let sitedata = Eliom_request_info.get_sitedata_sp ~sp in
  let cookie_info, secure =
    compute_cookie_info sitedata secure_o secure_ci cookie_info
  in
  let full_st_name =
    Eliom_common.make_full_state_name ~sp ~secure ~scope:cookie_scope
  in
  try
    let _old, ior =
      Lazy.force
        (Eliom_common.Full_state_name_table.find full_st_name !cookie_info)
    in
    match !ior with
    | Eliom_common.SCData_session_expired
      (* We do not trust the value sent by the client,
           for security reasons *)
    | Eliom_common.SCNo_data ->
        let v =
          new_data_cookie sitedata full_st_name
            sitedata.Eliom_common.session_data
        in
        ior := Eliom_common.SC v;
        v
    | Eliom_common.SC c ->
        (match set_session_group with
        | None -> ()
        | Some _session_group ->
            let fullsessgrp = fullsessgrp ~cookie_level ~sp set_session_group in
            let node =
              Eliommod_sessiongroups.Data.move sitedata
                c.Eliom_common.dc_session_group_node fullsessgrp
            in
            c.Eliom_common.dc_session_group_node <- node;
            c.Eliom_common.dc_session_group := fullsessgrp);
        c
  with Not_found ->
    let v =
      new_data_cookie sitedata full_st_name sitedata.Eliom_common.session_data
    in
    cookie_info :=
      Eliom_common.Full_state_name_table.add full_st_name
        (Lazy.from_val (None, ref (Eliom_common.SC v)))
        !cookie_info;
    v

let find_or_create_data_cookie =
  (find_or_create_data_cookie
    : ?set_session_group:string
      -> cookie_scope:Eliom_common.cookie_scope
      -> secure_o:bool option
      -> ?sp:Eliom_common.server_params
      -> unit
      -> Eliom_common.one_data_cookie_info
    :> ?set_session_group:string
       -> cookie_scope:[< Eliom_common.cookie_scope]
       -> secure_o:bool option
       -> ?sp:Eliom_common.server_params
       -> unit
       -> Eliom_common.one_data_cookie_info)

let find_data_cookie_only ~cookie_scope ~secure_o ?sp () =
  (* If the cookie does not exist, do not create it, raise Not_found.
     Returns the cookie info for the cookie *)
  let sp = Eliom_common.sp_of_option sp in
  let cookie_level = Eliom_common.cookie_level_of_user_scope cookie_scope in
  let (_, cookie_info, _), secure_ci =
    Eliom_common.get_cookie_info sp cookie_level
  in
  let sitedata = Eliom_request_info.get_sitedata_sp ~sp in
  let cookie_info, secure =
    compute_cookie_info sitedata secure_o secure_ci cookie_info
  in
  let full_st_name =
    Eliom_common.make_full_state_name ~sp ~secure ~scope:cookie_scope
  in
  let _, ior =
    Lazy.force
      (Eliom_common.Full_state_name_table.find full_st_name !cookie_info)
  in
  match !ior with
  | Eliom_common.SCNo_data -> raise Not_found
  | Eliom_common.SCData_session_expired ->
      raise Eliom_common.Eliom_Session_expired
  | Eliom_common.SC v -> v

(*****************************************************************************)
(** session data *)

let counttableelements = ref []
(* Here only for exploration functions *)

let create_volatile_table, create_volatile_table_during_session =
  let aux ~scope ~secure sitedata =
    let t = Eliom_common.SessionCookies.create 100 in
    let old_remove_session_data = sitedata.Eliom_common.remove_session_data in
    sitedata.Eliom_common.remove_session_data <-
      (fun cookie ->
        (* cookie is actually either a cookie or a a group name *)
        (* In session group tables, keys may be either group names,
            or a cookie values when no group name has been set. *)
        old_remove_session_data cookie;
        Eliom_common.SessionCookies.remove t cookie);
    let old_not_bound_in_data_tables =
      sitedata.Eliom_common.not_bound_in_data_tables
    in
    sitedata.Eliom_common.not_bound_in_data_tables <-
      (fun cookie ->
        old_not_bound_in_data_tables cookie
        && not (Eliom_common.SessionCookies.mem t cookie));
    counttableelements :=
      (fun () -> Eliom_common.SessionCookies.length t) :: !counttableelements;
    scope, secure, t
  in
  ( (fun ~scope ~secure ->
      let sitedata = Eliom_common.get_current_sitedata () in
      aux ~scope ~secure sitedata)
  , fun ~scope ~secure sitedata -> aux ~scope ~secure sitedata )
OCaml

Innovation. Community. Security.