Source file eliommod_pagegen.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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
open Lwt.Infix
let =
Cohttp.Header.add_opt headers
Ocsigen_header.Name.(to_string content_type)
(Printf.sprintf "%s; charset=utf-8"
Eliom_content_core.Html.D.Info.content_type)
let out =
let encode x = fst (Xml_print.Utf8.normalize_html x) in
Eliom_content_core.Html.Printer.pp ~encode ()
let make_response ? ~status body =
let body = Cohttp_lwt.Body.of_string (Format.asprintf "%a" out body)
and response =
let = headers_with_content_type headers in
Cohttp.Response.make ~status ~headers ()
in
Lwt.return (Ocsigen_response.make ~body response)
let def_handler e = Lwt.fail e
let update_cookie_table ?now sitedata (ci, sci) =
let now = match now with Some n -> n | None -> Unix.gettimeofday () in
let update_exp (service_cookies_info, data_cookies_info, pers_cookies_info) =
Eliom_common.Full_state_name_table.iter
(fun name (_oldvalue, newr) ->
match !newr with
| Eliom_common.SCData_session_expired | Eliom_common.SCNo_data ->
()
| Eliom_common.SC newc -> (
newc.Eliom_common.sc_exp :=
match !(newc.Eliom_common.sc_timeout) with
| Eliom_common.TGlobal -> (
let globaltimeout =
Eliommod_timeouts.find_global `Service name sitedata
in
match globaltimeout with
| None -> None
| Some t -> Some (t +. now))
| Eliom_common.TNone -> None
| Eliom_common.TSome t -> Some (t +. now)))
!service_cookies_info;
Eliom_common.Full_state_name_table.iter
(fun name v ->
let _oldvalue, newr = Lazy.force v in
match !newr with
| Eliom_common.SCData_session_expired | Eliom_common.SCNo_data ->
()
| Eliom_common.SC newc -> (
newc.Eliom_common.dc_exp :=
match !(newc.Eliom_common.dc_timeout) with
| Eliom_common.TGlobal -> (
let globaltimeout =
Eliommod_timeouts.find_global `Data name sitedata
in
match globaltimeout with
| None -> None
| Some t -> Some (t +. now))
| Eliom_common.TNone -> None
| Eliom_common.TSome t -> Some (t +. now)))
!data_cookies_info;
let module Expiry_tolerance = struct
let timeout_tolerance_factor = 0.01
let within_tolerance x y =
let diff = Float.abs (x -. y) in
diff < timeout_tolerance_factor *. Float.abs (x -. now)
let within_tolerance_opt x y =
match x, y with Some x, Some y -> within_tolerance x y | _ -> x = y
end
in
if Eliom_common.Full_state_name_table.exists
(fun _ v -> Lazy.is_val v)
!pers_cookies_info
then
Eliom_common.Full_state_name_table.fold
(fun name v thr ->
let thr2 =
Lazy.force v >>= fun (oldvalue, newr) ->
match !newr with
| Eliom_common.SCData_session_expired | Eliom_common.SCNo_data ->
Lwt.return ()
| Eliom_common.SC newc -> (
let newexp =
match !(newc.Eliom_common.pc_timeout) with
| Eliom_common.TGlobal -> (
let globaltimeout =
Eliommod_timeouts.find_global `Persistent name sitedata
in
match globaltimeout with
| None -> None
| Some t -> Some (t +. now))
| Eliom_common.TNone -> None
| Eliom_common.TSome t -> Some (t +. now)
in
match oldvalue with
| Some (_, oldti, oldexp, oldgrp)
when Expiry_tolerance.within_tolerance_opt oldexp newexp
&& oldti = !(newc.Eliom_common.pc_timeout)
&& oldgrp = !(newc.Eliom_common.pc_session_group)
&& newc.Eliom_common.pc_set_value = None ->
Lwt.return ()
| Some (_, _oldti, oldexp, _oldgrp)
when newc.Eliom_common.pc_set_value = None ->
Lwt.catch
(fun () ->
let cookieid =
Eliom_common.(
Hashed_cookies.to_string newc.pc_hvalue)
in
Eliommod_cookies.Persistent_cookies.replace_if_exists
cookieid
{ Eliommod_cookies.full_state_name = name
; expiry = newexp
; timeout = !(newc.Eliom_common.pc_timeout)
; session_group =
!(newc.Eliom_common.pc_session_group) }
>>= fun () ->
Eliommod_cookies.Persistent_cookies.Expiry_dates
.remove_cookie oldexp cookieid)
(function
| Not_found -> Lwt.return ()
| e -> Lwt.fail e)
| _ ->
Eliommod_cookies.Persistent_cookies.add
Eliom_common.(Hashed_cookies.to_string newc.pc_hvalue)
{ Eliommod_cookies.full_state_name = name
; expiry = newexp
; timeout = !(newc.Eliom_common.pc_timeout)
; session_group = !(newc.Eliom_common.pc_session_group)
})
in
thr >>= fun () -> thr2)
!pers_cookies_info Lwt.return_unit
else Lwt.return_unit
in
update_exp ci >>= fun () ->
update_exp sci
let execute now generate_page
({Eliom_common.all_cookie_info; tab_cookie_info; _} as info) sitedata
=
let%lwt result =
Lwt.catch
(fun () -> generate_page now info sitedata)
(fun e -> sitedata.Eliom_common.exn_handler e)
in
let%lwt () = update_cookie_table ~now sitedata all_cookie_info in
let%lwt () = update_cookie_table ~now sitedata tab_cookie_info in
Lwt.return result
(** Set expired sessions in request data *)
let set_expired_sessions ri closedservsessions =
if closedservsessions = ([], [])
then ()
else
Polytables.set
~table:(Ocsigen_request.request_cache ri.Ocsigen_extensions.request_info)
~key:Eliom_common.eliom_service_session_expired ~value:closedservsessions
open Ocsigen_extensions
let handled_method = function
| `GET | `HEAD | `POST | `PUT | `DELETE -> true
| _ -> false
let do_redirection status uri =
Ocsigen_extensions.Ext_found
(fun () ->
let response =
let =
Cohttp.Header.init_with Ocsigen_header.Name.(to_string header_id) uri
in
Cohttp.Response.make ~status ~headers ()
in
Lwt.return (Ocsigen_response.make response))
let gen_req_not_found ~is_eliom_extension ~sitedata ~previous_extension_err ~req
=
let req = Eliom_common.patch_request_info req in
let now = Unix.gettimeofday () in
let%lwt ri, si, previous_tab_cookies_info =
Eliom_common.get_session_info ~sitedata ~req 404
in
let all_cookie_info, closedsessions =
Eliommod_cookies.get_cookie_info now sitedata
si.Eliom_common.si_service_session_cookies
si.Eliom_common.si_data_session_cookies
si.Eliom_common.si_persistent_session_cookies
si.Eliom_common.si_secure_cookie_info
in
let (tab_cookie_info, closedsessions_tab), user_tab_cookies =
match previous_tab_cookies_info with
| Some (atci, utc) -> (atci, []), utc
| None ->
( Eliommod_cookies.get_cookie_info now sitedata
si.Eliom_common.si_service_session_cookies_tab
si.Eliom_common.si_data_session_cookies_tab
si.Eliom_common.si_persistent_session_cookies_tab
si.Eliom_common.si_secure_cookie_info_tab
, Ocsigen_cookie_map.empty )
in
set_expired_sessions ri (closedsessions, closedsessions_tab);
let rec gen_aux
({Eliom_common.request = ri; session_info = si; all_cookie_info; _} as
info)
=
let sp = Eliom_common.make_server_params sitedata info None None in
Lwt.with_value Eliom_common.sp_key (Some sp) @@ fun () ->
let genfun =
match si.Eliom_common.si_nonatt_info with
| Eliom_common.RNa_no ->
Eliom_route.get_page
| _ ->
Eliom_route.make_naservice
in
Lwt.catch
(fun () ->
let%lwt res = execute now genfun info sitedata in
let response, _ = Ocsigen_response.to_cohttp res
and all_user_cookies = Ocsigen_response.cookies res in
let%lwt cookies =
Eliommod_cookies.compute_cookies_to_send sitedata all_cookie_info
all_user_cookies
in
let res =
match
Ocsigen_request.header ri.Ocsigen_extensions.request_info
(Ocsigen_header.Name.of_string
Eliom_common_base.cookie_substitutes_header_name)
with
| Some _ ->
let response =
let =
Cohttp.Header.add
(Cohttp.Response.headers response)
Eliom_common_base.set_cookie_substitutes_header_name
(Eliommod_cookies.cookieset_to_json cookies)
in
{response with Cohttp.Response.headers}
in
Ocsigen_response.update ~response ~cookies res
| None -> Ocsigen_response.update ~cookies res
in
try
Polytables.get
~table:
(Ocsigen_request.request_cache ri.Ocsigen_extensions.request_info)
~key:Eliom_common.found_stop_key;
Lwt.return
(Ocsigen_extensions.Ext_found_stop (fun () -> Lwt.return res))
with Not_found ->
Lwt.return (Ocsigen_extensions.Ext_found (fun () -> Lwt.return res)))
(function
| Eliom_common.Eliom_Typing_Error l ->
Lwt.return
(Ocsigen_extensions.Ext_found
(fun () ->
make_response ~status:`Bad_request
(Eliom_error_pages.page_error_param_type l)))
| Eliom_common.Eliom_Wrong_parameter ->
let%lwt ripp =
match
Ocsigen_request.post_params req.request_info
ri.request_config.Ocsigen_extensions.uploaddir
ri.request_config.Ocsigen_extensions.maxuploadfilesize
with
| None -> Lwt.return []
| Some l -> l
in
let response =
Eliom_error_pages.page_bad_param
(try
ignore
@@ Polytables.get
~table:(Ocsigen_request.request_cache ri.request_info)
~key:Eliom_common.eliom_params_after_action;
true
with Not_found -> false)
(Ocsigen_request.get_params_flat ri.request_info)
(List.map fst ripp)
in
Lwt.return
@@ Ocsigen_extensions.Ext_found
(fun () -> make_response ~status:`Bad_request response)
| Eliom_common.Eliom_404 ->
Lwt.return (Ocsigen_extensions.Ext_next previous_extension_err)
| Eliom_common.Eliom_retry_with a -> gen_aux a
| Eliom_common.Eliom_do_redirection uri ->
Lwt.return
@@ do_redirection Ocsigen_header.Name.location `Temporary_redirect
uri
| Eliom_common.Eliom_do_half_xhr_redirection uri ->
Lwt.return
@@ do_redirection
(Ocsigen_header.Name.of_string
Eliom_common.half_xhr_redir_header)
`No_content uri
| e -> Lwt.fail e)
in
let info =
{ Eliom_common.request = ri
; session_info = si
; all_cookie_info
; tab_cookie_info
; user_tab_cookies }
in
match is_eliom_extension with
| Some ext -> Eliom_extension.run_eliom_extension ext now info sitedata
| None -> gen_aux info
let gen is_eliom_extension sitedata =
let open Ocsigen_extensions in
function
| Req_found _ -> Lwt.return Ext_do_nothing
| Req_not_found ((`Not_found as previous_extension_err), req)
when handled_method (Ocsigen_request.meth req.request_info) ->
gen_req_not_found ~is_eliom_extension ~sitedata ~previous_extension_err
~req
| Req_not_found (_, _ri) -> Lwt.return Ext_do_nothing