123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365# 1 "src/lib/eliom_service.server.ml"(* Ocsigen
* http://www.ocsigen.org
* 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.
*)includeEliom_service_baseletplain_service(typemgpgnpppngp')?(https=false)~path?keep_nl_params?priority~(meth:(m,gp,gn,pp,pn,_,gp')meth)()=letget_params,post_params=params_of_methmethandmeth=which_meth_internalmethinletredirect_suffix=Eliom_parameter.contains_suffixget_paramsinletpath=(matchredirect_suffixwith|None->path|Some_->path@[Eliom_common.eliom_suffix_internal_name])|>Url.remove_slash_at_beginning|>Url.change_empty_list|>Url.remove_internal_slashin(ifEliom_common.get_sp_option()=NonethenmatchEliom_common.global_register_allowed()with|Somecurrent_site_data->Eliom_common.add_unregistered(current_site_data())path|None->raise(Eliom_common.Eliom_site_information_not_available"service"));letreload_fun=Rf_client_funinmain_service~https~prefix:""~path~kind:`Service~meth?redirect_suffix?keep_nl_params?priority~get_params~post_params~reload_fun()letcreate_attached?name?(csrf_safe=false)?csrf_scope?csrf_secure?max_use?timeout?(https=false)?keep_nl_params~fallback~get_params~post_params~meth()=letis_post=is_post'methinletcsrf_scope=default_csrf_scopecsrf_scopeandget_params_type,post_params_type=ifis_postthen(get_params,Eliom_parameter.add_pref_paramsEliom_common.co_param_prefixpost_params)else(Eliom_parameter.add_pref_paramsEliom_common.co_param_prefixget_params,post_params)andk=attached_infofallbackin{pre_applied_parameters=fallback.pre_applied_parameters;get_params_type;post_params_type;send_appl_content=fallback.send_appl_content;service_mark=service_mark();max_use;timeout;meth;kind=`AttachedCoservice;info=(letatt_name=ifcsrf_safethenEliom_common.SAtt_csrf_safe(uniqueid(),(csrf_scope:>Eliom_common.user_scope),csrf_secure)elsematchnamewith|None->Eliom_common.SAtt_anon(new_state())|Somename->Eliom_common.SAtt_namednameinAttached{kwithget_name=(ifis_postthenk.get_nameelseatt_name);post_name=(ifnotis_postthenk.post_nameelseatt_name)});https=https||fallback.https;keep_nl_params=(matchkeep_nl_paramswith|None->fallback.keep_nl_params|Somek->k);client_fun=no_client_fun();reload_fun=Rf_client_fun}letcreate_attached_get=create_attached~meth:Get'~post_params:Eliom_parameter.unitletcreate_attached_post?name?csrf_safe?csrf_scope?csrf_secure?max_use?timeout?https?keep_nl_params~fallback~post_params()=letget_params=get_params_typefallbackincreate_attached~meth:Post'?name?csrf_safe?csrf_scope?csrf_secure?max_use?timeout?https?keep_nl_params~fallback~post_params~get_params()letcreate_attached_get_unsafe=create_attached_getletcreate_attached_post_unsafe=create_attached_postletcoservice'(typemgpgnpppn)?name?(csrf_safe=false)?csrf_scope?csrf_secure?max_use?timeout?(https=false)?(keep_nl_params=`Persistent)~(meth:(m,gp,gn,pp,pn,_,unit)meth)()=letget_params,post_params=params_of_methmethinletmeth=which_meth_internalmethandis_post=is_postmethinletcsrf_scope=default_csrf_scopecsrf_scopein{max_use;timeout;pre_applied_parameters=Eliom_lib.String.Table.empty,[];get_params_type=Eliom_parameter.add_pref_paramsEliom_common.na_co_param_prefixget_params;post_params_type=post_params;meth;kind=`NonattachedCoservice;info=Nonattached{na_name=(ifcsrf_safethenifis_postthenEliom_common.SNa_post_csrf_safe(uniqueid(),(csrf_scope:>Eliom_common.user_scope),csrf_secure)elseEliom_common.SNa_get_csrf_safe(uniqueid(),(csrf_scope:>Eliom_common.user_scope),csrf_secure)elsematchname,is_postwith|None,true->Eliom_common.SNa_post'(new_state())|None,false->Eliom_common.SNa_get'(new_state())|Somename,true->Eliom_common.SNa_post_name|Somename,false->Eliom_common.SNa_get_name);keep_get_na_params=true};https;keep_nl_params;send_appl_content=XNever;service_mark=service_mark();client_fun=no_client_fun();reload_fun=Rf_client_fun}letcreate?name?(csrf_safe=false)?csrf_scope?csrf_secure?max_use?timeout?(https=false)?(keep_nl_params=`Persistent)?priority(typemgpgnpppngp'att_co_ext_reg_rr)~(meth:(m,gp,gn,pp,pn,_,gp')meth)~(path:(att_,co_,gp')path_option)():(gp,pp,m,att_,co_,ext_,reg_,_,gn,pn,rr)t=matchpathwith|Pathpath->plain_service~https~keep_nl_params?priority~path~meth()|No_path->coservice'?name~csrf_safe?csrf_scope?csrf_secure?max_use?timeout~https~keep_nl_params~meth()letcreate_unsafe=createletcreate_ocaml=createletattach:fallback:(unit,unit,get,att,_,non_ext,'rg1,[<suff],unit,unit,'return1)t->service:('get,'post,'gp,non_att,co,non_ext,'rg2,([<`WithoutSuffix]as'sf),'gn,'pn,'return)t->unit->('get,'post,'gp,att,co,non_ext,non_reg,'sf,'gn,'pn,'return)t=fun~fallback~service()->let{na_name;_}=non_attached_infoserviceinletfallbackkind=attached_infofallbackinletopenEliom_commoninleterror_msg="attach' is not implemented for this kind ofservice. Please report a bug if you need this."inletget_name=matchna_namewith|SNa_get_s->SAtt_na_nameds|SNa_get's->SAtt_na_anons|SNa_get_csrf_safea->SAtt_na_csrf_safea|SNa_post__->fallbackkind.get_name(*VVV check *)|SNa_post'_->fallbackkind.get_name(*VVV check *)|SNa_post_csrf_safe_->fallbackkind.get_name(*VVV check *)|_->failwitherror_msg(*VVV Do we want to make possible to attach POST na coservices
on GET attached coservices? *)andpost_name=matchna_namewith|SNa_get__->SAtt_no|SNa_get'_->SAtt_no|SNa_get_csrf_safe_->SAtt_no|SNa_post_s->SAtt_na_nameds|SNa_post's->SAtt_na_anons|SNa_post_csrf_safea->SAtt_na_csrf_safea|_->failwitherror_msgin{servicewithservice_mark=service_mark();kind=`AttachedCoservice;pre_applied_parameters=fallback.pre_applied_parameters;info=Attached{fallbackkindwithget_name;post_name}}exceptionWrong_session_table_for_CSRF_safe_coserviceleteliom_appl_answer_content_type="application/x-eliom"(* If there is a client side process, we do an XHR with tab cookies *)letxhr_with_cookiess=ifis_externalsthenNoneelsematchs.send_appl_contentwith|XAlways->SomeNone|XNever->None(* actually this will be tested again later in
get_onload_form_creators *)|XSame_appl(_,tmpl)->Sometmpl(* Some an = current_page_appl_name *)(* for now we do not know the current_page_appl_name. We will know it
only after calling send. In case it is not the same name, we will
not send the onload_form_creator_info. *)letregister_eliom_modulenamef=Ocsigen_loader.set_module_init_functionnamefexceptionUnregistered_CSRF_safe_coserviceletregister_delayed_get_or_na_coservice~sp(k,scope,secure)=letf=trylettable=!(Eliom_state.get_session_service_table_if_exists~sp~scope:(scope:>Eliom_common.user_scope)?secure())inEliom_lib.Int.Table.findktable.Eliom_common.csrf_get_or_na_registration_functionswithNot_found->(lettable=Eliom_state.get_global_table()intryEliom_lib.Int.Table.findktable.Eliom_common.csrf_get_or_na_registration_functionswithNot_found->raiseUnregistered_CSRF_safe_coservice)inf~spletregister_delayed_post_coservice~sp(k,scope,secure)getname=letf=trylettable=!(Eliom_state.get_session_service_table_if_exists~sp~scope:(scope:>Eliom_common.user_scope)?secure())inEliom_lib.Int.Table.findktable.Eliom_common.csrf_post_registration_functionswithNot_found->(lettable=Eliom_state.get_global_table()intryEliom_lib.Int.Table.findktable.Eliom_common.csrf_post_registration_functionswithNot_found->raiseUnregistered_CSRF_safe_coservice)inf~spgetnameletset_delayed_get_or_na_registration_functiontableskf=tables.Eliom_common.csrf_get_or_na_registration_functions<-Eliom_lib.Int.Table.addkftables.Eliom_common.csrf_get_or_na_registration_functionsletset_delayed_post_registration_functiontableskf=tables.Eliom_common.csrf_post_registration_functions<-Eliom_lib.Int.Table.addkftables.Eliom_common.csrf_post_registration_functionsletremove_servicetable(typema)(service:(_,_,m,a,_,_,_,_,_,_,_)t)=matchinfoservicewith|Attachedattser->letkey_kind=which_meth_untypedserviceinletattserget=get_nameattserinletattserpost=post_nameattserinletsgpt=get_params_typeserviceinletsppt=post_params_typeserviceinEliom_route.remove_servicetable(sub_pathattser){Eliom_common.key_state=attserget,attserpost;Eliom_common.key_meth=key_kind}(ifattserget=Eliom_common.SAtt_no||attserpost=Eliom_common.SAtt_nothenEliom_parameter.(anonymise_params_typesgpt,anonymise_params_typesppt)else0,0)|Nonattachednaser->letna_name=na_namenaserinEliom_route.remove_naservicetablena_nameletunregister?scope?secure(typem)(service:(_,_,m,_,_,_,_,_,_,_,_)t)=letsp=Eliom_common.get_sp_option()inmatchscopewith|None|Some`Site->lettable=matchspwith|None->(matchEliom_common.global_register_allowed()with|Someget_current_sitedata->letsitedata=get_current_sitedata()insitedata.Eliom_common.global_services|_->raise(Eliom_common.Eliom_site_information_not_available"unregister"))|Some_->Eliom_state.get_global_table()inremove_servicetableservice|Some(#Eliom_common.user_scopeasscope)->(matchspwith|None->raise(failwith"Unregistering service for non global scope must be done during a request")|Somesp->lettable=!(Eliom_state.get_session_service_table~sp?secure~scope())inremove_servicetableservice)letclient_fun_=Nonelethas_client_fun_=false