123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111(**************************************************************************)(* *)(* Copyright 2018-2023 OCamlPro *)(* *)(* All rights reserved. This file is distributed under the terms of the *)(* GNU Lesser General Public License version 2.1, with the special *)(* exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)openLwt.InfixopenEzAPIopenEzAPIServerUtilsopenCohttpmoduleServer=Cohttp_lwt_unix.Serverletset_debug()=Cohttp_lwt_unix.Debug.activate_debug()letregister_ipreqiotime=letopenConduit_lwt_unixinmatchiowith|Domain_socket_|Vchan_->()|TCPtcp->match[@warning"-42"]Lwt_unix.getpeernametcp.fdwith|Lwt_unix.ADDR_INET(ip,_port)->letip=Ipaddr.to_string(Ipaddr_unix.of_inet_addrip)inletip=matchHeader.get(Request.headersreq)"x-forwarded-for"with|None->ip|Someip->ipinIp.registertimeip|Lwt_unix.ADDR_UNIX_path->()letheaders_from_cohttpreq=letheaders=refStringMap.emptyinHeader.iter(funsv->headers:=StringMap.add(String.lowercase_asciis)(String.split_on_char','v)!headers)(Request.headersreq);!headersletmeth_from_cohttpreq=matchRequest.methreqwith|#Meth.allasm->Somem|_->Noneletversion_from_cohttpreq=matchRequest.versionreqwith|#Req.versionasv->Somev|_->Noneletdebug_cohttpreq=debug"[%s] REQUEST: %s %S"(pp_time())(req|>Request.meth|>Code.string_of_method)(req|>Request.uri|>Uri.path_and_query);debugf~v:1(fun()->Header.iter(funsv->List.iter(funv->EzDebug.printf" %s: %s"sv)(String.split_on_char','v))(Request.headersreq))letdispatch?catchsioreqbody=lettime=GMTime.time()inregister_ipreqiotime;debug_cohttpreq;letheaders=headers_from_cohttpreqinletversion=version_from_cohttpreqinletpath_str,path,content_type,r=Req.request?version~headers~time(Request.urireq)inletmeth=meth_from_cohttpreqinCohttp_lwt.Body.to_stringbody>>=funbody->letws=WsCohttp.wsreqinLwt.catch(fun()->handle~ws?meth?content_types.server_kindrpathbody)(funexn->EzDebug.printf"In %s: exception %s"path_str@@Printexc.to_stringexn;matchcatchwith|None->Answer.server_errorexn>|=funa->`httpa|Somec->cpath_strexn>|=funa->`httpa)>>=function|`ws(Okra)->Lwt.returnra|`ws(Error_)->letheaders=Header.of_listdefault_access_control_headersinletstatus=Code.status_of_code501inServer.respond_string~headers~status~body:""()>|=fun(r,b)->`Response(r,b)|`http{Answer.code;body;headers}->letheaders=merge_headers_with_defaultheadersinletstatus=Code.status_of_codecodeindebug~v:(ifcode>=200&&code<300then1else0)"Reply computed to %S: %d"path_strcode;debug~v:3"Reply content:\n %s"body;letheaders=Header.of_listheadersinServer.respond_string~headers~status~body()>|=fun(r,b)->`Response(r,b)letcreate_server?catchserver_portserver_kind=lets={server_port;server_kind}inTimings.init(GMTime.time())@@Doc.nservices();ignore@@Doc.all_services_registered();letcallbackconnreqbody=dispatch?catchs(fstconn)reqbodyinleton_exn=function|Unix.Unix_error(Unix.EPIPE,_,_)->()|exn->EzDebug.printf"Server Error: %s"(Printexc.to_stringexn)inEzDebug.printf"Starting COHTTP server (port: %d)"server_port;Server.create~on_exn~mode:(`TCP(`Portserver_port))(Server.make_response_action~callback())letserver?catchservers=Lwt.join(List.map(fun(port,kind)->create_server?catchportkind)servers)